zoukankan      html  css  js  c++  java
  • 进程&信号&管道实践学习记录

    程序分析

    exec1.c & exect2.c & exect3.c

    程序代码 (以exect1.c为例,其他两个结构类似)

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
    	char	*arglist[3];
    
    	arglist[0] = "ls";
    	arglist[1] = "-l";
    	arglist[2] = 0 ;//NULL
    	printf("* * * About to exec ls -l
    ");
    	execvp( "ls" , arglist );
    	printf("* * * ls is done. bye");
    
    	return 0;
    }
    

    运行结果:

    结果显示代码“* * * ls is done. bye”没有打印出来。

    原因:因为调用execvp,execlp,execv时,内核将新程序载入到当前进程,替代当前进程的代码和数据。

    forkdemo1.c

    程序代码:

    #include	<stdio.h>
    #include    <sys/types.h>
    #include    <unistd.h>
    int main()
    {
    	int	ret_from_fork, mypid;
    	mypid = getpid();			   
    	printf("Before: my pid is %d
    ", mypid);
    	ret_from_fork = fork();
    	sleep(1);
    	printf("After: my pid is %d, fork() said %d
    ",
    		getpid(), ret_from_fork);
    
    	return 0;
    }
    

    运行结果:

    分析:fork()在父进程中返回子进程的pid,在子进程中返回0。

    forkdemo2.c

    程序代码:

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
    	printf("before:my pid is %d
    ", getpid() );
    	fork();
    	fork();
    	printf("aftre:my pid is %d
    ", getpid() );
    
    	return 0;
    }
    

    运行结果:

    分析:两次fork()共产生3个子进程,加上父进程总共有4个进程。

    forkdemo3.c

    程序代码:

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <unistd.h>
    
    int main()
    {
    	int	fork_rv;
    
    	printf("Before: my pid is %d
    ", getpid());
    
    	fork_rv = fork();		/* create new process	*/
    
    	if ( fork_rv == -1 )		/* check for error	*/
    	perror("fork");
    	else if ( fork_rv == 0 ){ 
    		printf("I am the child.  my pid=%d
    ", getpid());
    
    		exit(0);
    	}
    	else{
    		printf("I am the parent. my child is %d
    ", fork_rv);
    		exit(0);
    	}
    
    	return 0;
    }
    

    运行效果:

    forkdemo4.c

    程序代码:

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <unistd.h>
    
    int main()
    {
    	int	fork_rv;
    
    	printf("Before: my pid is %d
    ", getpid());
    
    	fork_rv = fork();		/* create new process	*/
    
    	if ( fork_rv == -1 )		/* check for error	*/
    		perror("fork");
    
    	else if ( fork_rv == 0 ){ 
    		printf("I am the child.  my pid=%d
    ", getpid());
    		printf("parent pid= %d, my pid=%d
    ", getppid(), getpid());
    		exit(0);
    	}
    
    	else{
    		printf("I am the parent. my child is %d
    ", fork_rv);
    		sleep(10);
    		exit(0);
    	}
    
    	return 0;
    }
    

    运行结果:

    forkgdb.c

    程序代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int  gi=0;
    int main()
    {
    	int li=0;
    	static int si=0;
    	int i=0;
    
    	pid_t pid = fork();
    	if(pid == -1){
    		exit(-1);
    	}
    	else if(pid == 0){
    		for(i=0; i<5; i++){
    			printf("child li:%d
    ", li++);
    			sleep(1);
    			printf("child gi:%d
    ", gi++);
    			printf("child si:%d
    ", si++);
    		}
    		exit(0);
    	
    	}
    	else{
    		for(i=0; i<5; i++){
    			printf("parent li:%d
    ", li++);
    			printf("parent gi:%d
    ", gi++);
    			sleep(1);
    			printf("parent si:%d
    ", si++);
    		}
    	exit(0);	
    
    	}
    	return 0;
    }
    

    运行效果:

    分析:运行结果说明了子进程与父进程并发运行。

    psh1.c

    #include	<stdio.h>
    #include	<stdlib.h>
    #include	<string.h>
    #include    <unistd.h>
    
    #define	MAXARGS		20				
    #define	ARGLEN		100				
    
    //将字符串内容当做命令来执行。
    int execute( char *arglist[] )
    {
    	execvp(arglist[0], arglist);		
    	perror("execvp failed");
    	exit(1);
    }
    
    char * makestring( char *buf )
    {
    	char	*cp;
    
    	buf[strlen(buf)-1] = '';		
    	cp = malloc( strlen(buf)+1 );		
    	if ( cp == NULL ){			
    		fprintf(stderr,"no memory
    ");
    		exit(1);
    	}
    	strcpy(cp, buf);		
    	return cp;			
    }
    
    int main()
    {
    	char	*arglist[MAXARGS+1];		
    	int		numargs;			
    	char	argbuf[ARGLEN];			
    
    	numargs = 0;
    	while ( numargs < MAXARGS )
    	{					
    		printf("Arg[%d]? ", numargs);
    		if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '
    ' )
    			arglist[numargs++] = makestring(argbuf);
    		else
    		{
    			if ( numargs > 0 ){		
    				arglist[numargs]=NULL;	
    				execute( arglist );	//将arglist中的字符串当做命令来执行。
    				numargs = 0;		
    			}
    		}
    	}
    	return 0;
    }
    

    运行结果:

    程序功能:输入字符串并将其当做命令执行。

    psh2.c

    程序代码:

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <string.h>
    #include    <sys/types.h>
    #include    <sys/wait.h>
    #include    <unistd.h>
    #include	<signal.h>
    
    #define	MAXARGS		20				
    #define	ARGLEN		100				
    
    char *makestring( char *buf )
    {
    	char	*cp;
    
    	buf[strlen(buf)-1] = '';		
    	cp = malloc( strlen(buf)+1 );		
    	if ( cp == NULL ){			
    		fprintf(stderr,"no memory
    ");
    		exit(1);
    	}
    	strcpy(cp, buf);		
    	return cp;			
    }
    
    void execute( char *arglist[] )
    {
    	int	pid,exitstatus;				
    
    	pid = fork();					
    	switch( pid ){
    		case -1:	
    			perror("fork failed");
    			exit(1);
    		case 0:
    			execvp(arglist[0], arglist);		
    			perror("execvp failed");
    			exit(1);
    		default:
    			while( wait(&exitstatus) != pid )
    				;
    			printf("child exited with status %d,%d
    ",
    					exitstatus>>8, exitstatus&0377);
    	}
    }
    
    int main()
    {
    	char	*arglist[MAXARGS+1];		
    	int		numargs;			
    	char	argbuf[ARGLEN];			
    
    	numargs = 0;
    	while ( numargs < MAXARGS )
    	{					
    		printf("Arg[%d]? ", numargs);
    		if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '
    ' )
    			arglist[numargs++] = makestring(argbuf);
    		else
    		{
    			if ( numargs > 0 ){		
    				arglist[numargs]=NULL;	
    				execute( arglist );	
    				numargs = 0;		
    			}
    		}
    	}
    	return 0;
    }
    

    运行结果:

    程序功能:不断产生新的子进程输入字符串命令。

    testbuf1

    程序代码:

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
    	printf("hello");
    	fflush(stdout);
    	while(1);
    }
    

    运行效果:

    testbuf2

    程序代码:

    #include <stdio.h>
    int main()
    {
    	printf("hello
    ");
    	while(1);
    }
    

    运行效果:

    testbuf3

    程序代码:

    #include <stdio.h>
    
    int main()
    {
    	fprintf(stdout, "1234", 5);
    	fprintf(stderr, "abcd", 4);
    }
    

    运行效果:

    分析:在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲的,会直接输出。所以输出结果为:abcd1234

    testpid.c

    程序代码:

    #include <stdio.h>
    #include <unistd.h>
    
    #include <sys/types.h>
    
    int main()
    {
    	printf("my pid: %d 
    ", getpid());//获取当前进程pid
    	printf("my parent's pid: %d 
    ", getppid());//获取当前进程父进程pid
    	return 0;
    }
    

    运行效果:

    testpp.c

    程序代码:

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
    	char **pp;
    	pp[0] = malloc(20);
    
    	return 0;
    }
    

    运行效果:

    testsystem.c

    程序代码:

    #include	<stdlib.h>
    
    int main ( int argc, char *argv[] )
    {
    
    	system(argv[1]);
    	system(argv[2]);
    	return EXIT_SUCCESS;
    }		
    
    • system函数:

    system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 返回值 =-1:出现错误 =0:调用成功但是没有出现子进程 >0:成功退出的子进程的id 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。

    运行效果:

    waitdemo1.c

    程序代码:

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <sys/types.h>
    #include    <sys/wait.h>
    #include    <unistd.h>
    
    #define	DELAY	4
    
    void child_code(int delay)
    {
    	printf("child %d here. will sleep for %d seconds
    ", getpid(), delay);
    	sleep(delay);
    	printf("child done. about to exit
    ");
    	exit(17);
    }
    
    void parent_code(int childpid)
    {
    	int wait_rv=0;		/* return value from wait() */
    	wait_rv = wait(NULL);//子进程成功结束返回子进程PID,没有子进程则返回-1。
    	printf("done waiting for %d. Wait returned: %d
    ", 
    			childpid, wait_rv);
    }
    int main()
    {
    	int  newpid;
    	printf("before: mypid is %d
    ", getpid());
    	if ( (newpid = fork()) == -1 )
    		perror("fork");
    	else if ( newpid == 0 )
    		child_code(DELAY);
    	else
    		parent_code(newpid);
    
    	return 0;
    }
    

    运行效果:

    waitdemo2.c

    程序代码:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>

    #define	DELAY	10
    
    void child_code(int delay)
    {
    	printf("child %d here. will sleep for %d seconds
    ", getpid(), delay);
    	sleep(delay);
    	printf("child done. about to exit
    ");
    	exit(27);
    }
    
    void parent_code(int childpid)
    {
    	int wait_rv;	
    	int child_status;
    	int high_8, low_7, bit_7;
    
    	wait_rv = wait(&child_status);
    	printf("done waiting for %d. Wait returned: %d
    ", childpid, wait_rv);
    
    	high_8 = child_status >> 8;     /* 1111 1111 0000 0000 */
    	low_7  = child_status & 0x7F;   /* 0000 0000 0111 1111 */
    	bit_7  = child_status & 0x80;   /* 0000 0000 1000 0000 */
    	printf("status: exit=%d, sig=%d, core=%d
    ", high_8, low_7, bit_7);
    }
    
    int main()
    {
    	int  newpid;
    
    	printf("before: mypid is %d
    ", getpid());
    
    	if ( (newpid = fork()) == -1 )
    		perror("fork");
    	else if ( newpid == 0 )
    		child_code(DELAY);
    	else
    		parent_code(newpid);
    }
    

    运行结果:

    argtest.c

    程序代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include "argv.h"
    
    int main(int argc, char *argv[]) {
    char delim[] = " 	";
    int i;
    char **myargv;
       int numtokens;
    
       if (argc != 2) {
         fprintf(stderr, "Usage: %s string
    ", argv[0]);
    	  return 1;
    }   
    if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) {
    	  fprintf(stderr, "Failed to construct an argument array for %s
    ", argv[1]);
     	 return 1;
    } 
    printf("The argument array contains:
    ");
    for (i = 0; i < numtokens; i++)
    	  printf("%d:%s
    ", i, myargv[i]);
    
       execvp(myargv[0], myargv);
    
       return 0;
    }
    

    功能:将输入字符串当做系统命令执行。

    运行结果:

    environ.c

    程序代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
    	printf("PATH=%s
    ", getenv("PATH"));
    	setenv("PATH", "hello", 1);
    	printf("PATH=%s
    ", getenv("PATH"));
    #if 0
    	printf("PATH=%s
    ", getenv("PATH"));
    	setenv("PATH", "hellohello", 0);
    	printf("PATH=%s
    ", getenv("PATH"));
    
    
    	printf("MY_VER=%s
    ", getenv("MY_VER"));
    	setenv("MY_VER", "1.1", 0);
    	printf("MY_VER=%s
    ", getenv("MY_VER"));
    	#endif
    	return 0;
    }
    

    运行效果:

    environvar.c

    运行代码:

    #include <stdio.h>
    int main(void)
    {
    	extern char **environ;
    	int i;
    	for(i = 0; environ[i] != NULL; i++)
    		printf("%s
    ", environ[i]);
    
    	return 0;
    }
    

    功能:打印环境变量。

    运行效果:

    sigactdemo.c

    程序代码:

    #include	<stdio.h>
    #include    <unistd.h>
    #include	<signal.h>
    #define	INPUTLEN	100
    void inthandler();	
    int main()
    {
    	struct sigaction newhandler;	
    	sigset_t blocked;	
    	char x[INPUTLEN];
    	newhandler.sa_handler = inthandler;//新的信号处理函数效果与signal()类似	
    	newhandler.sa_flags = SA_RESTART|SA_NODEFER
    	|SA_RESETHAND;//设置信号处理相关操作	
    	sigemptyset(&blocked);	//将blocked信号集初始化,并清空。
    	sigaddset(&blocked, SIGQUIT);//将SIGQUIT信号加入参数blocked信号集。	
    	newhandler.sa_mask = blocked;//暂时将block信号阻塞	
    	if (sigaction(SIGINT, &newhandler, NULL) == -1)
    		perror("sigaction");
    	else
    		while (1) {
    			fgets(x, INPUTLEN, stdin);
    			printf("input: %s", x);
    		}
    	return 0;
    }
    void inthandler(int s)
    {
    	printf("Called with signal %d
    ", s);
    	sleep(s * 4);
    	printf("done handling signal %d
    ", s);
    }
    

    sigation结构体:

    struct sigaction {
    
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, 	void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
    }
    
    • sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
    • sa_mask 指定在信号处理程序执行过程中,哪些信号应当被阻塞。默认当前信号本身被阻塞。
    • sa_restorer 已过时,POSIX不支持它,不应再使用。
    • sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
    • sa_flags还可以设置其他标志:
      • SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
      • SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
      • SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号

    运行效果:

    sigactdemo2.c

    #include <unistd.h>
    #include <signal.h>
    #include <stdio.h>
    
    void sig_alrm( int signo )
    {
    	/*do nothing*/
    }
    
    unsigned int mysleep(unsigned int nsecs)
    {
    	struct sigaction newact, oldact;
    	unsigned int unslept;
    
    	newact.sa_handler = sig_alrm;//设置处理函数
    	sigemptyset( &newact.sa_mask );//清空newact的阻塞信号集
    	newact.sa_flags = 0;//设置信号处理的其它操作为空
    	sigaction( SIGALRM, &newact, &oldact );//显式取消阻塞信号
    
    	alarm( nsecs );//设置闹钟
    	pause();
    
    	unslept = alarm ( 0 );//取消闹钟,并返回剩余时间
    	sigaction( SIGALRM, &oldact, NULL );
    
    	return unslept;
    }
    
    int main( void )
    {
    	while( 1 )
    	{
    		mysleep( 2 );
    		printf( "Two seconds passed
    " );
    	}
    
    	return 0;
    }
    

    运行效果:

    sigdemo1.c

    #include	<stdio.h>
    #include	<signal.h>
    void	f(int);			
    int main()
    {
    	int	i;
    	signal( SIGINT, f );//改变键盘ctril+C处理函数		
    	for(i=0; i<5; i++ ){		
    		printf("hello
    ");
    		sleep(2);
    	}
    
    	return 0;
    }
    
    void f(int signum)			
    {
    	printf("OUCH!
    ");
    }
    

    运行效果:

    sigdemo2.c

    #include	<stdio.h>
    #include	<signal.h>
    
    main()
    {
    	signal( SIGINT, SIG_IGN );//设置忽略Ctrl+C中断信号。
    
    	printf("you can't stop me!
    ");
    	while( 1 )
    	{
    		sleep(1);
    		printf("haha
    ");
    	}
    }
    

    运行效果:

    sigdemo3.c

    程序代码:

    #include	<stdio.h>
    #include    <string.h>
    #include	<signal.h>
    #include    <unistd.h>
    
    #define	INPUTLEN	100
    
    int main(int argc, char *argv[])
    {
    	void inthandler(int);
    	void quithandler(int);
    	char input[INPUTLEN];
    	int nchars;
    
    	signal(SIGINT, inthandler);//^C	
    	signal(SIGQUIT, quithandler);//^
    
    	do {
    		printf("
    Type a message
    ");
    		nchars = read(0, input, (INPUTLEN - 1));
    		if (nchars == -1)
    			perror("read returned an error");
    		else {
    			input[nchars] = '';
    			printf("You typed: %s", input);
    		}
    	}
    	while (strncmp(input, "quit", 4) != 0);
    	return 0;
    }
    
    void inthandler(int s)
    {
    	printf(" Received signal %d .. waiting
    ", s);
    	sleep(2);
    	printf("  Leaving inthandler 
    ");
    }
    
    void quithandler(int s)
    {
    	printf(" Received signal %d .. waiting
    ", s);
    	sleep(3);
    	printf("  Leaving quithandler 
    ");
    }
    

    运行效果:

    listargs.c

    程序代码

    #include	<stdio.h>
    
    main( int ac, char *av[] )
    {
    	int	i;
    
    	printf("Number of args: %d, Args are:
    ", ac);//ac为传入参数的个数。
    	for(i=0;i<ac;i++)
    		printf("args[%d] %s
    ", i, av[i]);
    
    	fprintf(stderr,"This message is sent to stderr.
    ");
    }
    

    运行效果:

    pipe.c

    #include	<stdio.h>
    #include    <stdlib.h>
    #include	<unistd.h>
    
    #define	oops(m,x)	{ perror(m); exit(x); }
    
    int main(int ac, char **av)
    {
    	int	thepipe[2],			
    		newfd,				
    		pid;				
    	//判断管道输入格式是否正确
    	if ( ac != 3 ){
    		fprintf(stderr, "usage: pipe cmd1 cmd2
    ");
    		exit(1);
    	}
    	//管道建立失败,输出错误信息
    	if ( pipe( thepipe ) == -1 )		
    		oops("Cannot get a pipe", 1);
    	//子进程创建失败,输出错误信息
    	if ( (pid = fork()) == -1 )			
    		oops("Cannot fork", 2);
    	
    	if ( pid > 0 ){			
    		close(thepipe[1]);	
    
    		if ( dup2(thepipe[0], 0) == -1 )//将thepipe[0]重定向到标准输入
    			oops("could not redirect stdin",3);
    
    		close(thepipe[0]);	
    		execlp( av[2], av[2], NULL);//试着执行av[2]中的命令
    		oops(av[2], 4);
    	}
    
    	close(thepipe[0]);		
    
    	if ( dup2(thepipe[1], 1) == -1 )//将thepipe[1]重定向到标准输出
    		oops("could not redirect stdout", 4);
    
    	close(thepipe[1]);		
    	execlp( av[1], av[1], NULL);//试着执行av[1]中的命令
    	oops(av[1], 5);
    }
    
    • pipe():

      1. 头文件 #include<unistd.h>

      2. 定义函数: int pipe(int filedes[2]);

      3. 函数说明: pipe()会建立管道,并将文件描述词由参数filedes数组返回。
        filedes[0]为管道里的读取端
        filedes[1]则为管道的写入端。

      4. 返回值: 若成功则返回零,否则返回-1,错误原因存于errno中。

    execlp():

    从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了。

    返回值:
    如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。

    运行效果:

    pipedemo2.c

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <string.h>
    #include    <unistd.h>
    
    
    #define	CHILD_MESS	"I want a cookie
    "
    #define	PAR_MESS	"testing..
    "
    #define	oops(m,x)	{ perror(m); exit(x); }
    
    main()
    {
    	int	pipefd[2];		
    	int	len;			
    	char	buf[BUFSIZ];		
    	int	read_len;
    
    	if ( pipe( pipefd ) == -1 )
    		oops("cannot get a pipe", 1);
    
    	switch( fork() ){
    		case -1:
    			oops("cannot fork", 2);
    
    		case 0:			
    			len = strlen(CHILD_MESS);
    			while ( 1 ){
    				if (write( pipefd[1], CHILD_MESS, len) != len )
    					oops("write", 3);
    				sleep(5);
    			}
    	
    		default:		
    			len = strlen( PAR_MESS );
    			while ( 1 ){
    				if ( write( pipefd[1], PAR_MESS, len)!=len )
    					oops("write", 4);
    				sleep(1);
    				read_len = read( pipefd[0], buf, BUFSIZ );
    				if ( read_len <= 0 )
    					break;
    				write( 1 , buf, read_len );
    			}
    	}
    }
    

    运行结果:

    pipedemo.c

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <string.h>
    #include	<unistd.h>
    
    int main()
    {
    	int	len, i, apipe[2];	
    	char	buf[BUFSIZ];		
    
    	if ( pipe ( apipe ) == -1 ){
    		perror("could not make pipe");
    		exit(1);
    	}
    	printf("Got a pipe! It is file descriptors: { %d %d }
    ", 
    						apipe[0], apipe[1]);
    
    
    	while ( fgets(buf, BUFSIZ, stdin) ){
    		len = strlen( buf );
    		if (  write( apipe[1], buf, len) != len ){	
    			perror("writing to pipe");		
    			break;					
    		}
    		for ( i = 0 ; i<len ; i++ )                     
    			buf[i] = 'X' ;
    		len = read( apipe[0], buf, BUFSIZ ) ;		
    		if ( len == -1 ){				
    			perror("reading from pipe");		
    			break;
    		}
    		if ( write( 1 , buf, len ) != len ){	//将标准输入写到标准输出	
    			perror("writing to stdout");		
    			break;					
    		}
    	}
    }
    

    运行结果:


    stdinerdir1.c

    程序代码:

    #include	<stdio.h>
    #include	<fcntl.h>
    
    int main()
    {
    	int	fd ;
    	char	line[100];
    
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    
    	close(0);
    	fd = open("/etc/passwd", O_RDONLY);//读取passwd文件到stdin
    	if ( fd != 0 ){
    		fprintf(stderr,"Could not open data as fd 0
    ");
    		exit(1);
    	}
    
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    }
    

    stdinredir2.c

    #include		<stdio.h>
    #include    <stdlib.h>
    #include	<fcntl.h>
    
    //#define	CLOSE_DUP		
    //#define	USE_DUP2	
    
    main()
    {
    	int	fd ;
    	int	newfd;
    	char	line[100];
    
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    
    	fd = open("data", O_RDONLY);	
    #ifdef CLOSE_DUP
    	close(0);
    	newfd = dup(fd);		
    #else
    	newfd = dup2(fd,0);	//将fd重定向到标准输入	
    #endif
    	if ( newfd != 0 ){
    		fprintf(stderr,"Could not duplicate fd to 0
    ");
    		exit(1);
    	}
    	close(fd);			
    
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    	fgets( line, 100, stdin ); printf("%s", line );
    }
    

    运行效果:(没有data文件,无法获取文件描述符,重定向失败)

    testtty.c

    #include <unistd.h>
    
    int main()
    {
    	char *buf = "abcde
    ";
    	write(0, buf, 6);//将字符串写到标准输入
    }
    

    运行效果:

    whotofile.c

    #include	<stdio.h>
    #include    <stdlib.h>
    #include    <unistd.h>
    
    int main()
    {
    	int	pid ;
    	int	fd;
    
    	printf("About to run who into a file
    ");
    
    	if( (pid = fork() ) == -1 ){
    		perror("fork"); exit(1);
    	}
    	if ( pid == 0 ){
    		close(1);				/* close, */
    		fd = creat( "userlist", 0644 );		/* then open *///以写的方式创建一个文件,因为前面关闭了文件描述符1,所以fd=1,为标准输出。
    		execlp( "who", "who", NULL );		/* and run	*///执行who命令,输出到文件表描述符1中。
    		perror("execlp");
    		exit(1);
    	}
    	if ( pid != 0 ){
    		wait(NULL);
    		printf("Done running who.  results in userlist
    ");
    	}
    
    	return 0;
    }
    

    运行结果:

    consumer.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define FIFO_NAME "/tmp/myfifo"
    #define BUFFER_SIZE PIPE_BUF
    
    
    int main()
    {
    	int pipe_fd;
    	int res;
    
    	int open_mode = O_RDONLY;
    	char buffer[BUFFER_SIZE + 1];
    	int bytes = 0;
    
    	memset(buffer, 0, sizeof(buffer));//数组置零
    
    	printf("Process %d opeining FIFO O_RDONLY 
    ", getpid());
    	pipe_fd = open(FIFO_NAME, open_mode);
    	printf("Process %d result %d
    ", getpid(), pipe_fd);
    
    	if (pipe_fd != -1) {
    		do {
    			res = read(pipe_fd, buffer, BUFFER_SIZE);
    			bytes += res;
    		} while (res > 0);
    		close(pipe_fd);
    	} else {
    		exit(EXIT_FAILURE);
    	}
    
    	printf("Process %d finished, %d bytes read
    ", getpid(), bytes);
    	exit(EXIT_SUCCESS);
    }
    

    运行效果:

    文件不存在,打开失败。

    文件存在读取成功。

    producer.c

    程序代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define FIFO_NAME "/tmp/myfifo"
    #define BUFFER_SIZE PIPE_BUF
    #define TEN_MEG (1024 * 1024 * 10)
    
    int main()
    {
    	int pipe_fd;
    	int res;
    	int open_mode = O_WRONLY;
    
    	int bytes = 0;
    	char buffer[BUFFER_SIZE + 1];
    	//判断文件是否存在。
    	if (access(FIFO_NAME, F_OK) == -1) {
    		res = mkfifo(FIFO_NAME, 0777);//创建一个FIFO文件
    		if (res != 0) {
    			fprintf(stderr, "Could not create fifo %s 
    ",
    			FIFO_NAME);
    			exit(EXIT_FAILURE);
    		}
    	}
    
    	printf("Process %d opening FIFO O_WRONLY
    ", getpid());
    	pipe_fd = open(FIFO_NAME, open_mode);
    	printf("Process %d result %d
    ", getpid(), pipe_fd);
    
    	if (pipe_fd != -1) {
    		while (bytes < TEN_MEG) {
    			res = write(pipe_fd, buffer, BUFFER_SIZE);
    			if (res == -1) {
    				fprintf(stderr, "Write error on pipe
    ");
    				exit(EXIT_FAILURE);
    			}
    			bytes += res;
    		}
    		close(pipe_fd);
    	} else {
    		exit(EXIT_FAILURE);
    	}
    
    	printf("Process %d finish
    ", getpid());
    	exit(EXIT_SUCCESS);
    }
    

    access():

    判断是否具有存取文件的权限
    相关函数
    stat,open,chmod,chown,setuid,setgid
    表头文件

    include<unistd.h>

    定义函数

    int access(const char * pathname, int mode);
    函数说明
    access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合:
    R_OK,W_OK,X_OK 和F_OK。
    R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。
    F_OK则是用来判断该文件是否存在。由于access()只作权限的核查,并不理会文件形态或文件内容,因此,如果一目录表示为“可写入”,表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理。例如,你会发现DOS的文件都具有“可执行”权限,但用execve()执行时则会失败。
    返回值
    若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-1。

    mkfifo()

    mkfifo函数的作用是在文件系统中创建一个文件(该文件之前必须不存在),该文件用于提供FIFO功能,即命名管道。前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。
    #include <sys/types.h>

      #include <sys/stat.h>
      int mkfifo( const char *pathname, mode_t mode );
    

    mkfifo函数需要两个参数,第一个参数(pathname)是将要在文件系统中创建的一个专用文件。第二个参数(mode)用来规定FIFO的读写权限。Mkfifo函数如果调用成功的话,返回值为0;如果调用失败返回值为-1。

    运行结果:

    遇到的问题及解决

    1.sigactdemo.c中的inthandler中的参数int s是怎么传进去的?

    解决方法:在博客园提问。

    inthandler被当做函数指针传给了newhandler.sa_handler
    后面调用int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
    它的第一个参数signum指定的信号编号就是用来设置这个信号的处理函数的。信号SIGINT序号为2。

    命令kill -l可以查看各信号的序号。

    2.运行testpp时遇到段错误(核心已转储)。

    解决方法:在博客园提问。

    二维数组越界申请空间。

    将代码改为

    pp=malloc(20);
    

    即可编译成功。

    参考资料

    《深入理解计算机系统》第8章异常控制流

  • 相关阅读:
    Java 泛型 泛型的约束与局限性
    Java 泛型 泛型方法
    Java 泛型 泛型数组
    Java 泛型 协变性、逆变性
    Java 泛型 协变式覆盖和泛型重载
    Java 泛型 泛型代码和虚拟机
    Insertion Sort List
    Remove Duplicates from Sorted List II
    String to Integer (atoi)
    SpringMvc源码入门
  • 原文地址:https://www.cnblogs.com/Ntime/p/5005432.html
Copyright © 2011-2022 走看看