初学进程编程案例解析

我是linux编程的初学者,进程编程是linux编程首先要学习的东西,往后要学习进程之间通讯的一些编程。下面的是进程编程的一些基本函数以及他们的相关注释。

1.用户标识(UID)和有效用户标识(EUID

使用getuid函数和geteuid函数来获取当前进程的用户标识和有效用户标识

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void){
       printf("Current process UID : %ld\n",(long)getuid());
       printf("Current porcess EUID : %ld\n",(long)geteuid());
      return 0;
}

运行结果:

Current process UID:500

Current process EUID:500

2. fork函数

通过fork函数并判断函数返回值,根据返回值来判断是在父进程还是子进程。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void){
       pid_t pid;
//fork函数如果返回值小于0,表示调用失败
//如果返回值为0,表示处于进程中,如果大于0,表示在父进程中
       if((pid=fork())<0){
              perror("Cannot create the new process");
              return 1;
       }else if(pid==0){
              printf("In the child process!\n");
              return 0;
       }else {
              printf("In the parent process!\n");
              return 0;
       }
}

运行结果:

In the child processs!!

In the parent process!!

我的运行结果是:

In the parent process!

In the child processs!

父进程和子进程到底哪个先执行?

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

调用fork函数后,其后代码会被父子进程分别执行。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void){
       fork();
       printf("Will be executed twice\n");
       return 0;
}

运行结果:

Will be excuted twice

Will be excuted twice

3. vfork函数

首先定义g_var为全局变量, var为局部变量,然后调用fork函数创建子进程,并在子进程对g_var变量和var变量进行修改。子进程在输出这两个变量值后退出,输出父进程中的这两个变量的取值情况。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int g_var=0;
int main(void){
       pid_t pid;
       int var=1;
       printf("process id:%ld\n",(long)getpid());
       printf("before execute the fork system call, g_var=%d var=%d\n",g_var,var);
       if((pid=fork())<0)
       {
              perror("Cannot create a new process");
              return 1;
       }
       else if(pid==0)
       {
             g_var++;
              var++;
              printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
              _exit(0);
       }
       else
       printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
       return 0;
}

运行结果:

Process id :24437

Before excute the fork system call,g_var=0 var=1

Process id :24438, g_var=1 var=2

Process id :24437, g_var=0 var=1

//我的是先执行父进程 再执行子进程

修改上面的程序,将fork函数的语句进行替换,使用vfork函数,将代码保存并运行

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int g_var=0;
int main(void){
       pid_t pid;
       int var=1;
         printf("process id:%ld\n",(long)getpid());
         printf("before execute the fork system call, g_var=%d var=%d\n",g_var,var);
       if((pid=vfork())<0){
             perror("Cannot create a new process");
              return 1;
       }else if(pid==0){
              g_var++;
              var++;
             printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
             _exit(0);
       }
       printf("process id : %ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
       return 0;
} 

运行结果:

Process id :24574

Before excute the fork system call,g_var=0 var=1

Process  child id :24575, g_var=1 var=2

Process parent id :24574, g_var=1 var=2

4  exec 函数族

execvp函数支持参数列表,使用参数列表将使程序获得更大的灵活性,程序通过读取agrv中的参数,实现对输入的shell命令的执行。

#include <stdio.h>
#include <unistd.h>
int main(int argc,char* argv[]){
       if(argc<2){
              printf("Usage:  %s path\n",argv[0]);
              return 1; 
       }
       execlp("/bin/ls","ls",argv[1],(char*)NULL);
       return 0;
}

通过命令行:

gcc exec.c -o exec

./exec

执行结果:Usage: ./exec path 

5  exit函数

使用atexit注册了一个在进程退出时的处理函数,该处理函数只是显示一段文字信息。Main函数退出时将调用exit函数,这样进程就会在退出时自动调用atexit注册的处理函数。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void do_at_exit(void)
{
       printf("You can see the output when the program terminates\n");
}
int main(){
       int flag;
       flag=atexit(do_at_exit);//atexit	登记一个函数,当程序使用exit正常退出时被登记的函数自动被调用.
       if (flag != 0) {
              printf("Cannot set exit function\n");
             return EXIT_FAILURE;//EXIT_FAILURE经库函数stdlib.h转换为一个非0值	用来指示程序失败的结束,一般用于exit().
       }
              exit(EXIT_SUCCESS);//EXIT_SUCCESS	经库函数stdlib.h转换为一个0值	用来指示程序成功的结束,一般用于exit()..
}

输出结果:You can see the output when the program terminates 

进程控制/与运行环境的沟通:

atexit:登记一个函数,当程序使用exit正常退出时被登记的函数自动被调用.

exit :程序正常终止。首先atexit()登记的函数按照登记的逆序被调用;如果多次调用atexit登记了多个函数,按照登记的逆序调用这些函数。如果一个函数被登记了多次,则程序正常退出时该函数也将被调用多次。然后所有缓冲区中的数据被写回(flushed);所有打开着的流被关闭;tmpfile函数创建的文件被删除。最后,控制权返回给调用环境,返回数值表示程序返回时的状态,0表示EXIT_SUCCESS, 1表示EXIT_FAILURE.

6  _exit函数

下面的程序和上面的除了退出函数不同,其他都一样。不同的是使用_exit函数退出时,不会执行atexit中注册的处理函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void do_at_exit(void)
{
       printf("You can see the output when the program terminates\n");
}
 
int main(){
       int flag;
       flag=atexit(do_at_exit);
       if (flag != 0) {
              printf("Cannot set exit function\n");
             return EXIT_FAILURE;
       }
     _exit(EXIT_SUCCESS);//_Exit	程序正常终止, 但atexit(), at_quick_exit(), signal()登记的函数不被调用; 打开的流、文件是否被关闭,由编译器的实现者决定
}

输出结果:什么也没有 

7  kill 函数发送信号

直接用kill函数给进程发送结束信号或是让程序自动退出。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc,char* argv[]){
       pid_t pid;
       int exit_code;
       pid=getpid();//getpid()用来取得目前进程的进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
       srand((unsigned)pid);
       exit_code=(int)(rand() % 256);
       sleep(10);/*本语句是:延时函数.延时10毫秒。sleep是阻塞线程函数,它会在当前语句阻塞一段时间,参数是以1/1000秒为单位的。执行sleep时当前线程放弃目前的时间片(在 10ms 内不会被再次调度),不参加资源的竞争,并且其他线程发送消息过来的时候,就没法响应,但同一程序的其它线程会照常工作。在DOS下,只有单线程,意味着死机。*/
       if(atoi(*(argv+1)) % 2){//atoi(n)会扫描参数n字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换,并将结果返回。返回值:返回转换后的整型数。
              printf("the child process id:%d receive signal SIGKILL\n",pid);
              kill(pid,9);//编号为9的kill信号,强行“杀掉”该进程
       }else{
              printf("the child process id:%d normally exit,exit_code is %0x\n",pid,exit_code);
              exit(exit_code);
       }
}

程序执行结果:

Segmentation fault (core dumped)

下面程序通过fork函数创建子进程,并调用execl函数执行上面的程序。为了方便了解程序运行情况,在父进程中显示了创建的子进程的进程号。在while循环中调用wait函数,跳出条件是wait函数放回值小于0,或wait_pid-1。这种情况下,所有的子进程都已经完全退出。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc,char* argv[]){
       pid_t pid,wait_pid;
       int status;
       int i;
       if(argc<4){
             printf("Usage: %s para1 para2 para3\n",argv[0]);
              return 1;
       }
       for(i=1;i<4;i++)
              if((pid=fork())==0)
                     execl("./p7.14","p7.14",argv[i],NULL);//Excel函数即是预先定义,执行计算、分析等处理数据任务的特殊公式。
              else
              printf("create the child process id: %d\n",pid);
       while((wait_pid=wait(&status)) && wait_pid!=-1)/*wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status 可以设成NULL。子进程的结束状态值请参考waitpid()。返回值如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno 中。*/
              printf("process id:%d exit,exit_code is %0x\n",wait_pid,status);
             return 0;
}

执行结果:Usage: ./kill-fork para1 para2 para3

8  waitpid函数

使用waitpid等待SIGSTOP,SIGCONTSIGKILL3种信号.

#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
   pid_t pid,wait_pid;
   int status;
   pid = fork();
   if (pid==-1)  {
  perror("Cannot create new process");
  exit(1);
  } 
else if (pid==0) {     
   printf("child process id: %ld\n", (long) getpid());
   pause();
   _exit(0);
   } 
else {                    
    do {
       wait_pid=waitpid(pid, &status, WUNTRACED | WCONTINUED);
        if (wait_pid == -1) {
            perror("cannot using waitpid function");
              exit(1);
        }
        if (WIFEXITED(status))
    printf("child process exites, status=%d\n", WEXITSTATUS(status));
       if(WIFSIGNALED(status))
     printf("child process is killed by signal %d\n", WTERMSIG(status));
       if (WIFSTOPPED(status))
     printf("child process is stopped by signal %d\n", WSTOPSIG(status));
        if (WIFCONTINUED(status))
    printf("child process resume running....\n");
    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
           exit(0);
     }
}

执行结果:

child process id: 3060

.....

一段时间后还是退不出来,最后强制关闭终端

9. 僵尸进程

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
 int main (void)
{
  pid_t pid;
   pid = fork();
  if(pid<0){
      perror("cannot create new process");
     exit(1);
  }
  if (pid>0)
    sleep (60);
  else
    exit (0);
  return 0;
} 

执行结果:无任何显示.....一段时间后照常其他命令

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值