linux进程共享内存通信示例
2015-12-08 18:07
567 查看
进程通信
以读、拷贝、写三个进程写作完成文件拷贝为例,操作流程大致为:主进程内申请共享信号量和共享内存区域,并对其做必要的初始化操作。然后再主进程中启动读、拷贝、写三个子进程。用共享信号量控制子进程的操作,用共享内存实现子进程通信。主进程持续等待,直至所有子进程执行完毕,然后释放信号量和共享内存。
申请信号量
传入一个key(2333),申请4个信号量int semid = semget(2333, 4, IPC_CREAT|0666); if(semid == -1) { return -1; }
申请共享内存
大小为4+BUF_SIZE+1,前4个字节用于存放每次读取的字节数(整数)//fork(".", 0)用于产生一个与当前目录有关的key const int BUF_SIZE = 1024; int segidS = shmget(ftok(".", 0), BUF_SIZE+5, IPC_CREAT|0666); if(segidS == -1) { return -1; } int segidT = shmget(ftok(".", 1), BUF_SIZE+5, IPC_CREAT|0666); if(segidT == -1) { return -1; }
启动子进程
get:负责从文件读至缓冲区Scopy:负责从缓冲区S复制至缓冲区T
put:负责从缓冲区T写至文件
pid_t p1, p2, p3; if((p1 = fork()) == 0) { execv("./get", NULL); } if((p2 = fork()) == 0) { execv("./copy", NULL); } if((p3 = fork()) == 0) { execv("./put", NULL); }
等待子进程执行
如果文件打开出现异常,则终止程序,否则copy进程会一直陷入等待,导致整个程序僵死int status; wait(&status); if(WEXITSTATUS(status)>1 && WEXITSTATUS(status)<5) { exit(-1); } wait(&status); if(WEXITSTATUS(status)>1 && WEXITSTATUS(status)<5) { exit(-1); } wait(&status); if(WEXITSTATUS(status)>1 && WEXITSTATUS(status)<5) { exit(-1); }
释放信号量及共享内存
将申请的信号亮和共享内存释放掉semctl(semid, 0, IPC_RMID, NULL); shmctl(segidS, IPC_RMID, NULL); shmctl(segidT, IPC_RMID, NULL);
附:全部源码
PV操作头文件:pv.h
定义了semun结构:这个结构类型semtrl()对信号量赋初值时需要自己定义。实现了简单的P、V操作。
#ifndef PV_H_INCLUDED #define PV_H_INCLUDED #include <sys/types.h> #include <sys/sem.h> #include <sys/ipc.h> union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ unsigned short *array; /* array for GETALL & SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ void *__pad; }; static inline void P(int semid, int index) { struct sembuf buf; buf.sem_num = index; buf.sem_op = -1; buf.sem_flg = 0; semop(semid, &buf, 1); } static inline void V(int semid, int index) { struct sembuf buf; buf.sem_num = index; buf.sem_op = 1; buf.sem_flg = 0; semop(semid, &buf, 1); } #endif // PV_H_INCLUDED
主进程:process.c
申请并初始化资源启动子进程
等待子进程
释放资源
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/shm.h> #include <sys/types.h> #include "pv.h" int main(int argc, char* argv[]) { //request for semaphore int semid = semget(2333, 4, IPC_CREAT|0666); if(semid == -1) { printf("create semaphore fail in copy\n"); return -1; } //init semaphore 1, 1, 0, 0 union semun arg; arg.val = 1; if(semctl(semid, 0, SETVAL, arg) == -1) { printf("set semaphore value fail\n"); return -1; } if(semctl(semid, 1, SETVAL, arg) == -1) { printf("set semaphore value fail\n"); return -1; } arg.val = 0; if(semctl(semid, 2, SETVAL, arg) == -1) { printf("set semaphore value fail\n"); return -1; }if(semctl(semid, 3, SETVAL, arg) == -1) { printf("set semaphore value fail\n"); return -1; } //reuqest for shared memory S and T const int BUF_SIZE = 1024; int segidS = shmget(ftok(".", 0), BUF_SIZE+5, IPC_CREAT|0666); if(segidS == -1) { return -1; } int segidT = shmget(ftok(".", 1), BUF_SIZE+5, IPC_CREAT|0666); if(segidT == -1) { return -1; } //bind shared memory S and T char* S; S = (char*)shmat(segidS, NULL, SHM_R|SHM_W); if(S == (void *)-1) { return -1; } char* T; T = (char*)shmat(segidT, NULL, SHM_R|SHM_W); if(T == (void *)-1) { return -1; } if(argc < 3) { printf("The process needs two parameters!\n"); return -1; } else if(argc > 3) { printf("Warning:there are too many parameters!Standard use:./process srcFile destFile\n"); } //input path strcpy(S, argv[1]); strcpy(T, argv[2]); printf("will copy file:%s to file:%s\n\n", S, T); //start 3 other processes int status; pid_t p1, p2, p3; if((p1 = fork()) == 0) { execv("./get", NULL); } if((p2 = fork()) == 0) { execv("./copy", NULL); } if((p3 = fork()) == 0) { execv("./put", NULL); } //wait for 3 processes wait(&status); if(WEXITSTATUS(status)>1 && WEXITSTATUS(status)<5) { exit(-1); } wait(&status); if(WEXITSTATUS(status)>1 && WEXITSTATUS(status)<5) { exit(-1); } wait(&status); if(WEXITSTATUS(status)>1 && WEXITSTATUS(status)<5) { exit(-1); } //clear semaphore and shared memory semctl(semid, 0, IPC_RMID, NULL); shmctl(segidS, IPC_RMID, NULL); shmctl(segidT, IPC_RMID, NULL); printf("\n\ncopy finish!\n"); return 0; }
读进程:get.c
每次读BUF_SIZE个字节至缓冲区S,并将实际读取的字节数送入S的前4个字节。#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/shm.h> #include <sys/types.h> #include "pv.h" int main() { int semid = semget(2333, 4, IPC_CREAT|0666); if(semid == -1) { printf("create semaphore fail in get\n"); exit(2); } const int BUF_SIZE = 1024; int segidS = shmget(ftok(".", 0), BUF_SIZE+5, IPC_CREAT|0666); if(segidS == -1) { exit(2); } char *S; S = (char *)shmat(segidS, NULL, SHM_R|SHM_W); if(S == (void *)-1) { exit(2); } FILE *fp; if((fp=fopen(S,"r"))==NULL){ printf("\nCannot open file strike any key exit!"); exit(2); } int num = 0; *((int*)S) = 0; while(1) { P(semid, 0); *((int*)S) = fread(S+4, 1, BUF_SIZE, fp); //printf("read data:%d\n", *((int*)S)); V(semid, 2); if(*((int*)S)<BUF_SIZE || feof(fp)) { break; } } shmctl(segidS, IPC_RMID, 0); fclose(fp); return 0; }
拷贝进程:copy.c
每次将缓冲区S的内容拷贝至缓冲区T#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/shm.h> #include <sys/types.h> #include "pv.h" int main() { int semid = semget(2333, 4, IPC_CREAT|0666); if(semid == -1) { printf("create semaphore fail in copy\n"); exit(3); } const int BUF_SIZE = 1024; int segidS = shmget(ftok(".", 0), BUF_SIZE+5, IPC_CREAT|0666); if(segidS == -1) { exit(3); } int segidT = shmget(ftok(".", 1), BUF_SIZE+5, IPC_CREAT|0666); if(segidT == -1) { exit(3); } char* S; S = (char*)shmat(segidS, NULL, SHM_R|SHM_W); if(S == (void *)-1) { exit(3); } char* T; T = (char*)shmat(segidT, NULL, SHM_R|SHM_W); if(T == (void *)-1) { exit(3); } while(1) { P(semid, 2); P(semid, 3); *((int*)T) = *((int*)S); memcpy(T+4, S+4, BUF_SIZE); //printf("copy data:%d\n", *((int*)T)); V(semid, 0); V(semid, 1); if(*((int*)T) < BUF_SIZE) break; } return 0; }
写进程:put.c
每次将缓冲区T实际有效的内容(字节大小为前4个字节所表示的整数)写入文件#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/shm.h> #include <sys/types.h> #include "pv.h" int main() { int semid = semget(2333, 4, IPC_CREAT|0666); if(semid == -1) { printf("create semaphore fail in put\n"); exit(4); } const int BUF_SIZE = 1024; int segidT = shmget(ftok(".", 1), BUF_SIZE+5, IPC_CREAT|0666); if(segidT == -1) { exit(4); } char* T; T = (char*)shmat(segidT, NULL, SHM_R|SHM_W); if(T == (void *)-1) { exit(4); } FILE *fp; if((fp=fopen(T,"w"))==NULL){ printf("\nCannot open file strike any key exit!"); exit(4); } int isFirst = 1; int count = 0; *((int*)T) = 0; while(1) { P(semid, 1); if(!isFirst) { count = *((int*)T); if(count > 0) fwrite(T+4, 1, count, fp); //printf("put data:%d\n", count); } V(semid, 3); if(isFirst) { isFirst = 0; } else if(count < BUF_SIZE) { break; } } fclose(fp); return 0; }
注意
分别编译三个源文件后,需要将其放在同一个文件目录下,然后运行:./process srcFile destFile
srcFile:源文件相对路径或绝对路径。
destFile:目标文件相对路径或绝对路径。
已测试过普通文本文件、.jpg、.gif、.zip、.mp3、.m4a等文件复制。
相关文章推荐
- Linux socket 初步
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- 基于 Linux 集群环境上 GPFS 的问题诊断
- 谁是桌面王者?Win PK Linux三大镇山之宝
- vivi下重新调整分区