首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

linux 进程间通信步骤综合分析

2013-10-12 
linux 进程间通信方法综合分析进程间通信,常用的方法有,pipe、popen(pclose)、命名pipe、Unix域套接字、消息队

linux 进程间通信方法综合分析

进程间通信,常用的方法有,pipe、popen(pclose)、命名pipe、Unix域套接字、消息队列、信号量、记录锁、共享内存。

这么多方法,到底不同方法应用场景是怎样的呢。

1、相关进程(父子进程)

pipe,一定是最简单的,由于子进程可以继承父进程的描述符,所以用2个pipe,就可以实现父子进程间的通信,例子后续给出。

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4.   
  5. #define BUF_SIZE 1024  
  6.   
  7. int main()  
  8. {  
  9.     char * str = "Hello world";  
  10.     char buf[BUF_SIZE] = {0};  
  11.       
  12.     int file_pipes[2] = {0};  
  13.   
  14.     int pipe_ret = pipe(file_pipes);  
  15.     if (-1 == pipe_ret)  
  16.     {  
  17.         printf("pipe failed\n");  
  18.         return -1;  
  19.     }  
  20.   
  21.     pid_t fork_ret = fork();  
  22.     if (-1 == fork_ret)  
  23.     {  
  24.         printf("fork failed\n");  
  25.         return -1;  
  26.     }  
  27.   
  28.     if (0 == fork_ret)  
  29.     {  
  30.         close(file_pipes[1]);  
  31.         int ret_num = read(file_pipes[0], buf, BUF_SIZE);  
  32.         printf("(%d), read %d bytes: %s\n", getpid(), ret_num, buf);  
  33.         sleep(1);  
  34.         return 0;  
  35.     }  
  36.     else  
  37.     {  
  38.         close(file_pipes[0]);  
  39.         int ret_num = write(file_pipes[1], str, strlen(str));  
  40.         printf("(%d), wirte %d bytes: %s\n", getpid(), ret_num, str);  
  41.         sleep(1);  
  42.         return 0;  
  43.     }  
  44.     return 0;  
  45.   
  46. }  
运行结果:
./pipe2 
(21653), wirte 11 bytes: Hello world
(21654), read 11 bytes: Hello world

<总结>需要注意的一点就是fork子进程, 子进程会继承父进程pipe(0)、pipe(1),其只能用一个pipe,所以需要close掉另外一个pipe,通过本例子,可以构造出一个父子进程同步的方法,fork之前pipe两个管道,一个用于父给子发送同步消息,一个用于子给父发送同步消息。

2、进程调用其它进程

输入参数、获取相应输出,用popen(pclose)最划算啦,例如程序用执行ls -l命令,要获取其输出,popen完全ok。下面给出一个简单的例子:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4.   
  5. #define BUF_SIZE 1000  
  6.   
  7. int main()  
  8. {  
  9.     FILE * read_fp = NULL;  
  10.     char buffer[BUF_SIZE] = {0};  
  11.   
  12.     read_fp = popen("ls -l", "r");  
  13.     if (NULL == read_fp)  
  14.     {  
  15.         return -1;  
  16.     }  
  17.   
  18.     fread(buffer, 1, BUF_SIZE, read_fp);  
  19.     printf("out put is \n %s \n", buffer);  
  20.       
  21.     pclose(read_fp);  
  22.   
  23.     return 0;  
  24.   
  25. }  


3、不相干进程

a、如果仅仅用于传递消息,信息量少,Unix域套接字、消息队列都ok,当然是用起来,前者更方便一些,其是用方法和一般的socket方法基本一样;

UNIX域:可以参考我写的另外一个帖子http://blog.csdn.net/beginning1126/article/details/8895738,当中有说明和例子,这里就不赘述了。


b、如果两个进程之前需要共享一大段内存数据,这时再采用Unix域套接字、消息队列就太浪费了,因为两者再传递内存时,都少不了内存的拷贝,共享内存首选,当然用于共享内存的同步,信号量、记录锁都可以,例子后续给出

信号量:可以参考我写的另外一个帖子http://blog.csdn.net/beginning1126/article/details/12520253,当中有说明和例子,这里就不赘述了。


下面给出一个通过信号量做同步,然后用共享内存共享数据的例子:

例子代码比较简陋,功能也比较单一,仅仅用于说明如何通过信号量来达到共享内存的互斥。

进程1:

[cpp] view plaincopy
  1. #include <memory.h>  
  2. #include <stdio.h>  
  3. #include <unistd.h>  //getpagesize(  )  
  4. #include <sys/ipc.h>  
  5. #include <sys/shm.h>  
  6. #include <sys/sem.h>  
  7.   
  8.   
  9.   
  10. #define MY_SHM_ID 1234  
  11. #define MY_SEM_ID 4321  
  12. #define MEM_SIZE 300  
  13.   
  14. union semun  
  15. {  
  16.     int val;  
  17.     struct semid_ds * buf;  
  18.     unsigned short * array;  
  19. };  
  20.   
  21. int semaphore_p(int sem_id) {  
  22.     struct sembuf sem_b;  
  23.     sem_b.sem_num = 0;  
  24.     sem_b.sem_op = -1;  
  25.     sem_b.sem_flg = SEM_UNDO;  
  26.   
  27.     semop(sem_id, &sem_b, 1);  
  28.   
  29.     return 0;  
  30. }  
  31.   
  32. int semaphore_v(int sem_id) {  
  33.     struct sembuf sem_b;  
  34.     sem_b.sem_num = 0;  
  35.     sem_b.sem_op = 1;  
  36.     sem_b.sem_flg = SEM_UNDO;  
  37.   
  38.     semop(sem_id, &sem_b, 1);  
  39.   
  40.     return 0;  
  41. }  
  42.   
  43.   
  44. int set_semvalue(int sem_id) {  
  45.     union semun sem_union;  
  46.     sem_union.val = 1;  
  47.   
  48.     if (-1 == semctl(sem_id, 0, SETVAL, sem_union))  
  49.     {  
  50.         return -1;  
  51.     }  
  52.     return 0;  
  53. }  
  54.   
  55. int del_semvalue(int sem_id) {  
  56.     union semun sem_union;  
  57.   
  58.     if (-1 == semctl(sem_id, 0, IPC_RMID, sem_union))  
  59.     {  
  60.         return -1;  
  61.     }  
  62.   
  63.     return 0;  
  64. }  
  65.   
  66.   
  67.   
  68. int main() {  
  69.     printf("page size: %d. \n", getpagesize());  
  70.       
  71.     // create share memory  
  72.     int shmid = 0;  
  73.     shmid = shmget(MY_SHM_ID, MEM_SIZE, 0666 | IPC_CREAT);  
  74.     if (-1 == shmid) {  
  75.         printf("create share memroy failed. \n");  
  76.         return -1;  
  77.     }  
  78.     printf("create a shared memory success, shmid: %d. \n", shmid);  
  79.   
  80.     // create sem id  
  81.     int sem_id = semget((key_t)MY_SEM_ID, 1, 0666 | IPC_CREAT);  
  82.     set_semvalue(sem_id);  
  83.     printf("get a sem id: %d\n", sem_id);  
  84.   
  85.     // attach share memory  
  86.     unsigned char * mem = NULL;  
  87.     mem = shmat(shmid, (const void*)0, 0);  
  88.     if (-1 == (size_t)mem) {  
  89.         printf("failed in shmat. \n");  
  90.         return -1;  
  91.     }  
  92.     memset(mem, 0, MEM_SIZE);  
  93.     printf("attach shm: %p\n", mem);  
  94.       
  95.     sleep(5);  
  96.       
  97.     // get share memory status  
  98.     struct shmid_ds shmds;  
  99.     memset(&shmds, 0, sizeof(struct shmid_ds));  
  100.     int ret = 0;  
  101.     ret = shmctl(shmid, IPC_STAT, &shmds);  
  102.     if (-1 == ret) {  
  103.         printf("failed in shmctl. \n");  
  104.         return -1;  
  105.     }      
  106.     printf("size of memory segment is %d. \n", shmds.shm_segsz);  
  107.     printf("numbre of attaches %d. \n", (int)shmds.shm_nattch);  
  108.   
  109.   
  110.     while(1) {  
  111.         semaphore_p(sem_id);  
  112.         unsigned char * p = mem;  
  113.         int len = p[0];  
  114.         p[len+1] = 'w';  
  115.         p[0] += 1;  
  116.         semaphore_v(sem_id);  
  117.         sleep(1);  
  118.         if (len >= 254) {  
  119.             break;  
  120.         }  
  121.     }  
  122.   
  123.     mem[0] = 'b';  
  124.     printf("result is %s\n", mem);  
  125.     del_semvalue(sem_id);  
  126.   
  127.     // detach share memory   
  128.     ret = shmdt(mem);  
  129.     if(-1 == ret) {  
  130.         printf("failed in shmdt");  
  131.         return -1;  
  132.     }  
  133.   
  134.     // delete share memory  
  135.     ret = shmctl(shmid, IPC_RMID, 0);  
  136.     if(-1 == ret) {  
  137.         printf("failded in delete shm. \n");  
  138.         return -1;  
  139.     }  
  140.   
  141.     return 0;  
  142. }  

进程2:

[cpp] view plaincopy
  1. #include <memory.h>  
  2. #include <stdio.h>  
  3. #include <unistd.h>  //getpagesize(  )  
  4. #include <sys/ipc.h>  
  5. #include <sys/shm.h>  
  6. #include <sys/sem.h>  
  7.   
  8. #define MY_SHM_ID 1234  
  9. #define MY_SEM_ID 4321  
  10. #define MEM_SIZE 300  
  11.   
  12. union semun  
  13. {  
  14.     int val;  
  15.     struct semid_ds * buf;  
  16.     unsigned short * array;  
  17. };  
  18.   
  19. int semaphore_p(int sem_id) {  
  20.     struct sembuf sem_b;  
  21.     sem_b.sem_num = 0;  
  22.     sem_b.sem_op = -1;  
  23.     sem_b.sem_flg = SEM_UNDO;  
  24.   
  25.     semop(sem_id, &sem_b, 1);  
  26.   
  27.     return 0;  
  28. }  
  29.   
  30. int semaphore_v(int sem_id) {  
  31.     struct sembuf sem_b;  
  32.     sem_b.sem_num = 0;  
  33.     sem_b.sem_op = 1;  
  34.     sem_b.sem_flg = SEM_UNDO;  
  35.   
  36.     semop(sem_id, &sem_b, 1);  
  37.   
  38.     return 0;  
  39. }  
  40.   
  41.   
  42. int set_semvalue(int sem_id) {  
  43.     union semun sem_union;  
  44.     sem_union.val = 1;  
  45.   
  46.     if (-1 == semctl(sem_id, 0, SETVAL, sem_union))  
  47.     {  
  48.         return -1;  
  49.     }  
  50.     return 0;  
  51. }  
  52.   
  53. int del_semvalue(int sem_id) {  
  54.     union semun sem_union;  
  55.   
  56.     if (-1 == semctl(sem_id, 0, IPC_RMID, sem_union))  
  57.     {  
  58.         return -1;  
  59.     }  
  60.   
  61.     return 0;  
  62. }  
  63.   
  64.   
  65.   
  66. int main() {  
  67.     printf("page size: %d. \n", getpagesize());  
  68.       
  69.     // create share memory  
  70.     int shmid = 0;  
  71.     shmid = shmget(MY_SHM_ID, 0, 0);  
  72.     if (-1 == shmid) {  
  73.         printf("get share memroy failed. \n");  
  74.         return -1;  
  75.     }  
  76.     printf("get a shared memory success, shmid: %d. \n", shmid);  
  77.   
  78.     // create sem id  
  79.     int sem_id = semget((key_t)MY_SEM_ID, 1, 0666 | IPC_CREAT);  
  80.     printf("get a sem id: %d\n", sem_id);  
  81.   
  82.     // attach share memory  
  83.     unsigned char * mem = NULL;  
  84.     mem = shmat(shmid, (const void*)0, 0);  
  85.     if (-1 == (size_t)mem) {  
  86.         printf("failed in shmat. \n");  
  87.         return -1;  
  88.     }  
  89.     printf("attach shm: %p\n", mem);  
  90.       
  91.   
  92.       
  93.     // get share memory status  
  94.     struct shmid_ds shmds;  
  95.     memset(&shmds, 0, sizeof(struct shmid_ds));  
  96.     int ret = 0;  
  97.     ret = shmctl(shmid, IPC_STAT, &shmds);  
  98.     if (-1 == ret) {  
  99.         printf("failed in shmctl. \n");  
  100.         return -1;  
  101.     }      
  102.     printf("size of memory segment is %d. \n", shmds.shm_segsz);  
  103.     printf("numbre of attaches %d. \n", (int)shmds.shm_nattch);  
  104.   
  105.   
  106.     while(1) {  
  107.         semaphore_p(sem_id);  
  108.         unsigned char * p = mem;  
  109.         int len = p[0];  
  110.         p[len+1] = 'r';  
  111.         p[0] += 1;  
  112.         semaphore_v(sem_id);  
  113.         sleep(1);  
  114.         if (len >= 254) {  
  115.             break;  
  116.         }  
  117.     }  
  118.   
  119.     mem[0] = 'b';  
  120.     printf("result is %s\n", mem);  
  121.   
  122.     // detach share memory   
  123.     ret = shmdt(mem);  
  124.     if(-1 == ret) {  
  125.         printf("failed in shmdt");  
  126.         return -1;  
  127.     }  
  128.   
  129.     return 0;  
  130. }  

运行结果:

./shm1& 

./shm2
page size: 4096. 
get a shared memory success, shmid: 1605632. 
get a sem id: 1966082
attach shm: 0x2aca081e4000
size of memory segment is 300. 
numbre of attaches 2. 
result is bwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwrwr

<总结1>:通过运行结果可以看出,w、r,个数相等,同时交替出现,信号量很好的完成对共享内存互斥的工作。当然例子代码很简陋,关于信号量的部分代码有重复,完全可以单独抽出来进行重构,是在懒得改了,看官见谅下吧。

<总结2>:虽然说信号量能够完成对共享内存的互斥,但是这还远远不能满足我们对共享内存同步的要求,比如说,一个写进程,一个读进程,写进程完成对共享内存的写操作之后需要通知读进程来读取内存,当读进程完成读取操作之后,需要通知写进程继续写内容,这种同步操作,如果通过信号量貌似费劲了一点,可以通过UNIX域socket来实现共享内存的同步操作。


c、命名管道,貌似也可以,但是没怎么用过。


<注>很多书中提到STREAMS,由于其不是linux系统默认安装,需要添加附加包,本文章暂不讨论

热点排行