第二十一天:进程间的通信及守护进程

  进程的定义:一个其中运行着一个或者多个线程的地址空间和这些线程所需要的系统资源。通俗的说就是正在运行的程序。可以使用ps -ajx查看进程,每个进程都会被分配一个唯一的数字编号,为进程标识符(PID)父进程的描述符称为(PPID),STAT表示系统进程的运行状态,其中,S表示睡眠,R表示可运行,D表示等待,T表示停止,Z表示死进程或僵尸进程(子进程存在,父进程死亡,编写代码绝对不能出现)。

  使用fork函数创建进程。fork复制当前进程,在进程表中创建一个新的表项,新的表项中的许多属性与当前的进程是相同的。新的进程有自己的数据空间、环境、文件描述付。

  下面的代码是简单的创建进程getpid和getppid分别获得进程号和父进程号:

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 
 4 int main()
 5 {
 6     printf("haha\n");
 7 
 8     pid_t pid = 0;
 9     pid = fork();
10     if(pid < 0){
11         perror("fork error");
12         return 1;
13     }
14     if(pid == 0){
15         printf("this is child pid is %d,ppid is %d\n",getpid(),getppid());
16     }
17     if(pid > 0){
18         sleep(1);
19         printf("this is parent pid is %d,ppid is %d\n",getpid(),getppid());
20     }
21     printf("hello world\n");
22 }

   在子进程中对文件加写锁,在父进程中获得是哪个进程对文件加的锁:

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 #include<fcntl.h>
 4 #include<stdio.h>
 5 
 6 int main()
 7 {
 8     int fd = 0;
 9     fd = open("history",O_RDWR);
10     if(fd < 0){
11         perror("open");
12         return 1;
13     }
14     int file_size = lseek(fd,0,SEEK_END);
15     lseek(fd,0,SEEK_SET);
16     pid_t pid;
17     pid = fork();
18     struct flock lock;
19     if(pid > 0){
20         lock.l_type = F_WRLCK;    
21         lock.l_whence = SEEK_SET;
22         lock.l_start = 0;
23         lock.l_len =file_size; 
24         int ret = fcntl(fd,F_SETLK,&lock);
25         if(ret < 0){
26             perror("fcntl");
27             return 1;
28         }
29         printf("lock type is F_RDLCK %d\n" ,F_RDLCK);
30         printf("getpid is %d\n" ,getpid());
31         while(1);
32     }
33     if(pid == 0){
34         sleep(1);
35         lock.l_type = F_RDLCK;    
36         lock.l_whence = SEEK_SET;
37         lock.l_start = 0;
38         lock.l_len =file_size; 
39         int ret = fcntl(fd,F_GETLK,&lock);
40         if(ret < 0){
41             perror("fcntl");
42             return 1;
43         }
44         printf("lock pid is %d\n" ,lock.l_pid);
45         printf("lock type is %d\n" ,lock.l_type);
46         printf("getppid is %d\n" ,getppid());
47     }
48 }

   进程的通信方式有三种,信号量、无名管道、命名管道。其中信号量的不能传太多的信息。无名管道仅仅适合父子进程之间的通信,这三种方式的代码比较简单。

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 #include<stdlib.h>
 4 #include<fcntl.h>
 5 #include<signal.h>
 6 
 7 void hello(int sig){
 8     printf("hello wrold \n");
 9 }
10 int main()
11 {
12     pid_t pid = 0;
13     pid = fork();
14     if(pid < 0){
15         perror("fork");
16         return 1;
17     }
18     if(pid  == 0){
19         signal(SIGINT,hello);
20         printf("this is child,%d\n",getpid());
21     }
22     if(pid  >  0 ){
23         printf("child pid id %d\n",pid);
24         int ret = kill(pid,SIGINT);
25         if(ret < 0){
26             perror("ret");
27             return 1;
28         }
29     }
30 }
信号量

   这个代码中要注意的是,kill表示送信号,可以使用kill -l 查看可以传输的信号量。singal函数对进来的信号有三种操作,无视,默认,处理函数。

不能传输 3 和 9 信号量。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 
 5 int main()
 6 {
 7     int fd[2];
 8     int ret = pipe(fd);
 9     if(ret < 0){
10         perror("pipe");
11         return 1;
12     }
13     pid_t pid ;    
14     pid = fork();
15     if(pid < 0){
16         perror("fork");
17         return 1;
18     }
19     if(pid == 0){
20         sleep(1);
21         close(fd[1]);
22         char data[20] = {0};
23         ret = read(fd[0],data,20);
24         if(ret < 0){
25             perror("read");
26             return 1;
27         }
28         printf("data is %s",data);
29         close(fd[0]);
30         
31     }
32     if(pid  >  0){
33         close(fd[0]);
34         char *data= "hello world\n";
35         ret = write(fd[1],data,20);
36         if(ret < 0){
37             perror("write");
38             return 1;
39         }
40         close(fd[1]);
41         wait(NULL);
42     }
43 
44 }
无名管道

   在执行前使用mkfifo创建管道文件 。

 1 #include<stdio.h>
 2 #include<fcntl.h>
 3 
 4 int main()
 5 {
 6     int fd = 0;
 7     fd = open("fo",O_RDWR);
 8     if( fd < 0){
 9         perror("open");
10         return 1;
11     }
12     int ret  = write(fd,"hahahah",7);
13     if( ret < 0){
14         perror("write");
15         return 1;
16     }
17 
18     close(fd);
19 }
命名管道_写
 1 #include<stdio.h>
 2 #include<fcntl.h>
 3 
 4 int main()
 5 {
 6     int fd = 0;
 7     fd = open("fo",O_RDWR);
 8     if( fd < 0){
 9         perror("open");
10         return 1;
11     }
12     char data[1024] = {0};
13     int ret  = read(fd,data,1024);
14     if( ret < 0){
15         perror("read");
16         return 1;
17     }
18     printf("data is %s\n",data);
19 
20     close(fd);
21 
22 }
命名管道_读

   今天最重要的是守护进程的使用,定义:在linux或者unix操作系统中在系统的引导的时候会开启很多服务,这些服务就叫做守护进程。为了增加灵活性,root可以选择系统开启的模式,这些模式叫做运行级别,每一种运行级别以一定的方式配置系统。守护进程是脱离于终端并且在后台运行的进程。

  编写守护进程是死规矩。记住五个步骤就可以了。下面的函数是使用守护进程编写日志文件. 

 1 #include<unistd.h>
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<time.h>
 5 #include<fcntl.h>
 6 
 7 int main(){
 8     pid_t pid;
 9     pid = fork();
10     if( pid > 0)
11         exit(EXIT_SUCCESS);
12     setsid();
13     chdir("/");
14     umask(0);
15     close(0);
16     close(1);
17     close(2);
18 
19     int fd = open("/var/log/bunfly",O_RDWR|O_CREAT,0644);
20     if(fd < 0){
21         perror("open");
22         return 1;
23     }
24     printf("fd is %d\n",fd);
25     char showtime[100] = {0};
26     int ret = 0;
27     while(1){
28         time_t today;
29         time(&today);
30         struct tm *p = gmtime(&today);
31         sprintf(showtime,"year is %d ,mount is %d ,days is %d ,hour is %d ,min is %d ,sec is %2d\n",p->tm_year +1900,p->tm_mon+1,p->tm_mday,(p->tm_hour+8)%24,p->tm_min,p->tm_sec);
32         ret = write(fd,showtime,71);
33         sleep(10);
34     }
35 
36 
37 }

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。