linux 之进程间通信-------------InterProcess Communication

  进程间通信至少可以通过传送打开文件来实现,不同的进程通过一个或多个文件来传递信息,事实上,在很多应用系统里,都使用了这种方法。但一般说来,进程间 通信(IPC:InterProcess Communication)不包括这种似乎比较低级的通信方法。Unix系统中实现进程间通信的方法很多,而且不幸的是,极少方法能在所有的Unix系 统中进行移植(唯一一种是半双工的管道,这也是最原始的一种通信方式)。而Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信 方法:管道、消息队列、共享内存、信号量、套接口等等。

  1、管道(pipe)

  管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,

    无名管道用于父进程和子进程间的通信,

    有名管道用于运行于同一台机器上的任意两个进程间的通信。

  无名管道由pipe()函数创建:

    #include  <unistd.h>

    int pipe(int  filedis[2]);

  参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开;filedes[1]的输出是filedes[0]的输入

linux 之进程间通信-------------InterProcess Communication
 1  1 #include <stdio.h>
 2  2 #include <string.h>
 3  3 #include <stdlib.h>
 4  4 #include <errno.h>
 5  5 #include <unistd.h>
 6  6 
 7  7 #define INPUT 0
 8  8 #define OUTPUT 1
 9  9 
10 10 int main()
11 11 {
12 12     int file_descriptors[2];
13 13     pid_t pid;
14 14     char buf[256];
15 15     char send1[256];
16 16     int returned_count;
17 17     
18 18     //创建无名管道
19 19     pipe(file_descriptors);
20 20     //创建子进程
21 21     if((pid=fork()) == -1)
22 22     {
23 23         printf("Error in fork\n");
24 24         exit(1);
25 25     }
26 26     //执行子进程
27 27     if(pid == 0)
28 28     {
29 29         printf("int the child process....\n");
30 30         fgets(send1,256, stdin);
31 31 
32 32         //子进程向父进程写数据,关闭管道的读端;
33 33         close(file_descriptors[INPUT]);
34 34         write(file_descriptors[OUTPUT], send1, strlen(send1));
35 35         exit(0);
36 36     }
37 37     else //执行父进程
38 38     {
39 39         printf("int the parent process...\n");
40 40         //父进程从管道读取子进程写的数据,关闭管道的写端
41 41         close(file_descriptors[OUTPUT]);
42 42         returned_count = read(file_descriptors[INPUT], buf, sizeof(buf));
43 43         printf("%d bytest of data received from child process: %s\n"
44 44                 ,returned_count,buf);
45 45     }
46 46 
47 47     return 0;
48 48 }
49 ////////////////////////
50 [root@cp ~]# ./a.out
51 int the parent process...
52 int the child process....
53 lkfjasldkf
54 11 bytest of data received from child process: lkfjasldkf
linux 之进程间通信-------------InterProcess Communication

  在linux系统下,有名管道可由两种方式创建:命令行方式mknod  系统调用 和函数mkfifo。

下面的两种途径都在当前目录下生成了一个名为myfifo的有名管道:

    方式一:mkfifo("myfifo" ,  "rw");

    方式二:mknod  myfifo  p

  生成了有名管道后,就可以使用一般的文件I/O函数如open, close, read, write等来对它进行操作。

2、消息队列

3、共享内存

  共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但现实中并不常用,因为它控制存取的将是实际的物理内存,在linux系统下,这只有通过限制linux系统存取的内存才可以做到,这当然不太实际。常用的方式是通过shmxxx函数族来实现利用共享内存进行存储的。

  首先是用的函数是shmget,它获得一个共享存储标识符。

  #include <sys/types.h>

  #include <sys/ipc.h>

  #include <sys/shm.h>

  int shmget(key_t  key, int  size,  int flag);

  这个函数有点类似malloc函数,系统按照请求分配size大小的内存用作共享内存。linux系统内核中每个IPC结构都有一个非负整数的标识符,这样对一个消息队列发送消息时总要引用标识符就可以了。这个标识符是内核由IPC结构的关键字得到的,这个关键字,就是上面第一个函数的key。 数据类型key_t是头文件sys/types.h 中定义的,它是一个长整形的数据。

  当共享内存创建后,其余进程可以调用shmat() 将其连接到自身的地址空间中;

  void  *shmat(int  shmid, void *addr,  int  flag);

  shmid 为shmget函数返回的共享存储标识符, addr 和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地址, 进程可以对此进程进行读写操作;

  使用共享存储来实现进程间通信的注意点是对数据存取的同步,必须确保当一个进程去读取数据时,它所想要的数据已经写好了。通常,信号量被要来实现对共享存储数据存取的同步,另外,可以通过使用shmctl函数设置共享存储内存的某些标志位如SHM_LOCK,

SHM_UNLOCK等来实现。

4、信号量

  信号量称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况,一般来说,为了获得共享资源,进程需要执行下列操作:

  1、测试控制该资源的信号量

  2、若此信号量的值为正,则允许进行使用该资源。进程将信号量减1

  3、若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直到信号量大于0.进程被唤醒,转入步骤1;

  4、当进程不再使用一个信号量控制的资源时,信号量加1。如果当时有进程正在睡眠等待此信号量,则唤醒此进程。

维护信号量状态的是Linux内核操作系统而不是用户进程。我们可以从头文件/usr/scr/linux/include/linux/sem.h中看到内核用来维护信号量状态的各个结构的定义。信号量是一个数据集合,用户可以单独使用这一集合的每个元素。要调用的第一个函数是semget,用以获得一个信号量ID;

  

  

  

linux 之进程间通信-------------InterProcess Communication

上一篇:Linux 环境下如何使 Chrome 浏览器字体更漂亮


下一篇:【代码笔记】iOS-动画的跳转