本文转自:http://blog.csdn.net/pcliuguangtao/article/details/6455118
- /*GUN/Linux进程有两种基本类型:内核线程和用户进程。
- 用户进程由fork()和clone()创建。内核线程是由内核中的kernel_thread()创建。
- 使用fork()创建子进程的时候,系统为它复制了父进程使用的内存部分映像,但是开始时他们都指向同一块内存,
- 但是把内存页面标记为copy-on-write。当任何一个进程试图向这些内存中写入数据时,就会产生一组新的内存页面由这个进程私有。
- 这提高了创建新进程的效率,因为内存空间的复制推迟到发生写操作的时候。默认情况下,子进程继承文件描述符、内容映像以及CPU状态(如PC和寄存器分配)。
- 在调用fork的时候,父进程当时所有的变量对子进程都是可见的。但在fork执行完之后,父进程变量的任何改动对子进程来说都是不可见的。
- */
- /*传统的进程API
- fork 创建一个新的子进程
- wait 将进程挂起直到任意一个子进程退出
- waitpid 将进程挂起直到指定的子进程退出
- signal 注册一个新的信号句柄
- pause 将进程挂起直到捕获到信号
- kill 向某个指定进程发送信号
- raise 向当前进程发送信号
- exec 将当前进程映像用一个新的进程映像替换
- exit 正常终止当前进程(退出)
- */
- //第一个进程实例
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/types.h>
- int main( )
- {
- pid_t myPid;
- pid_t myParentPid;
- gid_t myGid;
- uid_t myUid;
- myPid=getpid( );
- myParentPid=getppid( );
- myGid=getgid( );
- myUid=getuid( );
- printf( "my process id is %d/n",myPid );
- printf( "my parent's process id is %d/n",myParentPid );
- printf( "my user id is %d/n",myUid );
- printf( "my group id is %d/n",myGid );
- return 0;
- }
- //调用fork的应用实例
- /*
- 注意fork首先把CPU的控制权交给子进程。
- fork的返回值:
- On success, the PID of the child process is returned in the parent,
- and 0 is returned in the child. On failure, -1 is returned in the parent,
- no child process is created, and errno is set appropriately.
- */
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/wait.h>
- int main( )
- {
- pid_t ret;
- int status,i;
- int role=-1;
- ret=fork( );
- if( ret==0 ) //child process
- {
- printf( "Child:this is the child process ( pid %d )/n",getpid( ) );
- for( i=0;i<6;++i )
- {
- printf( "Child: at count %d /n ",i );
- sleep( 1 );
- }
- role=1;
- }
- else if( ret>0 ) //parent process ,ret is the child process's pid
- {
- printf( "Parent:this is the parent process ( pid %d )/n",getpid( ) );
- for( i=0;i<6;++i )
- {
- printf( "Parent: at count %d /n ",i );
- sleep( 1 );
- }
- wait( &status );
- role=0;
- }
- else
- {
- printf( "Parent:Error trying to fork( )( %s )/n",strerror(errno));
- }
- printf ( "%s:Exiting.../n",( (role==0)?"Parent":"Child" ) ); //both parent and child process execute
- return 0;
- }
- /*信号,即GUN/Linux中进程的回调符号。可以为某个进程注册为在某事件发生时接受信号或
- 是在某个默认操作退出时忽略信号。
- */
- //为捕获信号注册句柄实例
- #include <stdio.h>
- #include <sys/types.h>
- #include <signal.h>
- #include <unistd.h>
- void catch_ctlc( int sig_num )
- {
- printf( "/nCaught Ctrl+C/n" );
- fflush( stdout );
- return; //可有可无
- }
- int main( )
- {
- //查看系统信号列表:man 7 signal
- signal( SIGINT,catch_ctlc );
- printf( "Go ahead,make my day/n" );
- //pause()causes the calling process (or thread) to sleep until a signal is delivered
- pause( );
- return 0;
- }
- /************发出信号****************/
- /*
- kill()可以向任意一个具有相应权限的进程发送信号并发挥作用;
- raise( sig )可以向自身进程发送信号
- */
- //从子进程向父进程发出一个信号
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <signal.h>
- #include <errno.h>
- void usr1_handler( int sig_num )
- {
- printf( "Parent ( %d ) got the SIGUSR1/n",getpid( ) );
- }
- int main( )
- {
- pid_t ret;
- int status;
- int role=-1;
- ret=fork( );
- if( ret>0 )
- {
- printf( "Parent:this is the parent process ( pid %d )/n",getpid( ) );
- signal( SIGUSR1,usr1_handler );
- role=0;
- pause( );
- printf( "Parent:waiting for child exit/n" );
- ret=wait( &status );
- }
- else if( ret==0 )
- {
- printf( "Child:this is the child process ( pid %d )/n",getpid( ) );
- role=1;
- sleep( 1 ); //注意,当程序中出现sleep()的时候,就要注意对输出产生的滞后影响
- printf( "Child:Sending SIGUSR1 to pid %d/n",getppid( ) ); //此处的‘/n’不仅有换行的作用,还有刷新stdout的作用
- //kill(pid,signal)可用于向某个进程发送信号
- kill( getppid( ),SIGUSR1 );
- sleep( 2 );
- }
- else
- {
- printf( "Parent:Error trying to fork( )( %s )/n",strerror(errno));
- }
- printf("/n%s:Exiting.../n",( (role==0)?"Parent":"Child" ));
- return 0;
- }
- /*这个例子中父子进程都没有发送SIGUSR1信号
- 这个例子可用于展示进程间进行异步通讯的有力方法
- ./test &
- kill -s 10 -p parent'pid // 10 represent SIGUSR1
- kill -s SIGUSR1 -p child'pid
- */
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <signal.h>
- #include <error.h>
- void usr1_handler( int sig_num )
- {
- printf( "Process ( %d ) got the SIGUSR1/n",getpid( ) );
- }
- int main( )
- {
- pid_t ret;
- int status;
- int role=-1;
- signal( SIGUSR1,usr1_handler );
- ret=fork( );
- if( ret>0 )
- {
- printf("This is parent process ( pid %d )/n",getpid( ));
- role=0;
- printf( "Parent process waiting for signal/n" );
- pause( );
- printf( "Parent process waiting for child exit/n" );
- ret=wait( &status );
- }
- else if( ret==0 )
- {
- printf( "This is the child process ( pid %d )/n",getpid( ) );
- role=1;
- pause( );
- }
- else
- {
- printf( "Can't create the child process!/n" );
- }
- printf( "%s:Exiting.../n",( role==0 )?"Parent":"Child" );
- return 0;
- }
- //使用execlp的简单shell解释实例
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <wait.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MAX_LENGTH 80
- int main( )
- {
- int status;
- pid_t childpid;
- char cmd[ MAX_LENGTH+1 ];
- char* sret;
- funcloop:
- while( 1 )
- {
- printf( "mysh>" );
- sret=fgets( cmd,sizeof( cmd ),stdin);
- printf( "your command is :%s/n",cmd );
- if( sret==NULL )
- {
- printf( "You have input nothing! Please input command:/n" );
- goto funcloop;
- //exit( -1 );
- }
- if( !strncmp(cmd, "bye",3 ) ) exit( 0 );
- cmd[ strlen( cmd )-1 ]=0;
- childpid=fork( );
- if( childpid==0 )
- {
- execlp( cmd,cmd,NULL);
- }
- else if( childpid>0 )
- {
- waitpid( childpid,&status,0 );
- goto funcloop;
- }
- }
- free( cmd );
- return 0;
- }
- /*参数和进程环境方面的问题
- int execve( const char* filrname,char* const argv[ ],char* const envp[ ] );
- char* envp[ ]={"PATH=/bin","FOO=99",NULL};
- ...
- ret=execve( command,args,envp );
- 变量envp提供了一系列变量,为新创建的进程设置了环境。
- */
- /*unsigned int alarm( unsigned int secs )
- alarm在预先设定的时间长度达到时会发出一个SIGALRM信号,
- 在其他函数超时的情况下非常有用。
- */
- #include <stdio.h>
- #include <unistd.h>
- #include <signal.h>
- #include <string.h>
- #define MAX_BUFFER 80
- void wakeup( int sig_num )
- {
- raise( SIGKILL );
- }
- int main( )
- {
- char buffer[ MAX_BUFFER+1 ];
- int ret;
- signal( SIGALRM,wakeup );
- printf( "You have 3 seconds to enter your password/n" );
- alarm( 3 );
- ret=read( 0,buffer,MAX_BUFFER );
- //取消SIGALRM消息,以0参调用alarm即可
- alarm( 0 );
- if( ret==-1 )
- printf( "Password wrong/n" );
- else
- {
- buffer[ strlen( buffer )-1 ]=0;
- printf( "User entered: %s/n",buffer );
- }
- return 0;
- }
- /*exit函数
- viod exit( int status );
- 传入exit的参数会返回给父进程,为wait或waitpid调用提供所需要的状态信息。
- exit调用时还会向父进程发送SIGCHLD信号,释放当前进程所占用的资源。
- 如果进程注册了atexit或on_exit函数,这些函数也会在退出时执行,调用顺序与它们的注册顺序相反。
- */
- /*
- POSIX标准信号API函数:sigaction( )
- int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
- sigaction()提供的机制比传统的信号句柄更先进,而且有更强的兼容性。因此,应当使用sigaction来取代signal。
- */
- //演示使用sigaction注册信号句柄的简单应用
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <unistd.h>
- #include <errno.h>
- static int stopChild=0;
- void sigHandler( int sig,siginfo_t* siginfo,void* ignore )
- {
- printf( "Got SIGUSR1 from %d/n",siginfo->si_pid );
- stopChild=1;
- }
- int main( )
- {
- pid_t ret;
- int status;
- int role=-1;
- ret=fork( );
- if( ret>0 )
- {
- printf( "Parent:this is the parent process ( pid %d )/n",getpid( ) );
- //let the child init
- sleep( 1 );
- kill( ret,SIGUSR1 );
- ret=wait( &status );
- role=0;
- }
- else if( ret==0 )
- {
- struct sigaction act;
- printf( "This is the child process ( pid %d )/n",getpid( ) );
- act.sa_flags=SA_SIGINFO; //使用sa_sigaction指向的方法作为消息函数
- act.sa_sigaction=sigHandler; //指向特定方法
- sigaction( SIGUSR1,&act,0 );
- printf( "Child waiting.../n" );
- while( !stopChild );
- role=1;
- }
- else
- {
- printf( "Parent: Error trying to fork( )( %d )/n",errno );
- }
- printf( "%s:Exiting.../n",( ( role==0 )?"Parent":"Child" ) );
- return 0;
- }