您的位置:首页 > 运维架构 > Linux

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:负责从文件读至缓冲区S

copy:负责从缓冲区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 通信 内存