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

  进程的定义:一个其中运行着一个或者多个线程的地址空间和这些线程所需要的系统资源。通俗的说就是正在运行的程序。可以使用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 }
时间: 2024-10-19 13:00:36

第二十一天:进程间的通信及守护进程的相关文章

linux 进程间的通信

现在linux使用的进程间通信方式:(1)管道(pipe)和有名管道(FIFO)(2)信号(signal)(3)消息队列(4)共享内存(5)信号量(6)套接字(socket) 为何进行进程间的通信:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.资源共享

Linux进程间的通信方法简介

一.本地进程间的通信方式: 1.管道(pipe) 利用管道文件可以进行进程间数据的通信,通常是具有血缘关系的父子进程间的通信方式. 管道通信为半双工模式,父子进程可以通过调用内核中的read()和write()命令来向管道文件进行读写操作. 管道通信是基于硬盘内的文件,所以I/O速度较低. 2.消息队列 消息队列是一种类似链表的数据结构,存放于内存中,因此I/O速度较管道更快,通过ipcs -q命令可以查看当前系统中被创建的消息队列. 多个不同进程可以使用同一个消息队列进行通信,消息队列中的数据

python全栈开发day32-进程创建,进程同步,进程间的通信,进程池

一.内容总结 1.进程创建 1) Process:两种创建一个新进程的方法: 1.实例化Process,通过args=(,)元组形式传参,2创建类继承Process,类初始化的时候传参数 2) p.join(),阻塞主进程,执行完p进程后,释放 3)  守护进程 ,守护主程序代码执行完毕,p.daemon = True import time from multiprocessing import Process def func(): while True: print('is alive')

Android 使用AIDL实现进程间的通信

在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成. AIDL(android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作.关于AIDL的编写规则我在这里就不多介绍了,读者可以到网上查找一下相关资料. 接下来,我就演示一个操作AIDL的最基本的流程. 首先,我

进程间的通信如何实现

进程间的通信如何实现 版权声明:本文为博主原创文章,未经博主允许不得转载.

Linux进程间的通信

一.管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: A. 管道是半双工的,数据只能向一个方向流动: B. 需要双工通信时,需要建立起两个管道: C. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程): D. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中. 匿名管道的创建:该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义;因此,一

【转】使用AIDL实现进程间的通信之复杂类型传递

使用AIDL实现进程间的通信之复杂类型传递 首先要了解一下AIDL对Java类型的支持. 1.AIDL支持Java原始数据类型. 2.AIDL支持String和CharSequence. 3.AIDL支持传递其他AIDL接口,但你引用的每个AIDL接口都需要一个import语句,即使位于同一个包中. 4.AIDL支持传递实现了android.os.Parcelable接口的复杂类型,同样在引用这些类型时也需要import语句.(Parcelable接口告诉Android运行时在封送(marsha

Linux进程间的通信方法

linux进程间的通信方法总结如下 通过fork函数把打开文件的描述符传递给子进程 通过wait得到子进程的终结信息 通过加锁的方式,实现几个进行共享读写某个文件 进行间通过信号通信,SIGUSR1和SIGUSR2实现用户定义功能 利用pipe进行通信 FIFO文件进行通信 mmap,几个进程映射到同一内存区 SYS IPC 消息队列,信号量(很少用) UNIX Domain Socket,常用

进程间的通信:管道

进程间的通信:管道 Linux中将命令联系到一起使用实际上就是把一个进程的输出通过管道传递给另一个进程的输入,这些都是shell封装好的,对标准输入和输出流进行了重新连接,使数据流从键盘输入经过两个程序最终输出到屏幕上.如下: cmd1|cmd2 进程管道 在两个程序之间传递数据最简单的方法就是使用popen()和pclose()了.原型如下: #include <stdio.h> FILE *popen(const char *command, const char *open_mode);