Linux中写进程与读进程的通信(shm、sem)

工作原理示意图:

 

 

 

简单说明:

 

eNB process是写进程,UE process是读进程。首先在他们之间设置一块shared memory,其中前三个变量用于管理这个shared memory

 

shmid由三个信号量组成:

  • 互斥信号量SEM_MUTEX:保证shared memory不会同时被两个进程访问。
  • 可读资源信号量SEM_RD:当前shared memory中已被eNB process写好但还没有被UE process读取的shm_unit数量。初始化为shm_unit的大小SHMLEN
  • 可写资源信号量SEM_WR:当前shared memory中已被UE process读取但还没有被eNB process改写的shm_unit数量。初始化为0

 

shm_st中的shm_unit是一个环形缓冲区,当前写和读的指针分别是wr_ptrrd_ptr,均初始化为0。每写完一个unitwr_ptr自加1。每读完一个unitrd_ptr自加1。当这两个指针等于shm_unit的大小SHMLEN时,将它们重置为0

 

程序清单:

 

#include #include #include #include #include #include #include #include #define DEBUG #define SEM_NUM 3 #define SEM_MUTEX 0 #define SEM_RD 1 #define SEM_WR 2 #define SHM_KEY 7007 #define SEM_KEY 1413 #define SHMSIZE 4096 #define SHMLEN 7 typedef union _SEMUN { int val; struct semid_ds * buf; unsigned short * array; struct seminfo * __buf; } SEMUN; typedef struct _SHM_UNIT { int pack_len; char pack_cont[SHMSIZE]; }SHM_UNIT; typedef struct _SHM_ST { int semid; int wr_ptr; int rd_ptr; SHM_UNIT unit[SHMLEN]; } SHM_ST; typedef struct _PACK { int length; char * addr; } PACK; void ipc_init(int shmid) { SEMUN semun; void * shm = (void *)NULL; SHM_ST * shm_st; int sem_val, semid; semid = semget((key_t)IPC_PRIVATE, SEM_NUM, 0666 | IPC_CREAT); if(semid == -1) { perror("[ipc_init] semget failed"); exit(EXIT_FAILURE); } printf("[ipc_init] semid = %d/n", semid); /* set value of the 3 semaphores */ /* mutex */ semun.val = 1; if(semctl(semid, SEM_MUTEX, SETVAL, semun) == -1) { perror("[ipc_init] semctl failed"); exit(EXIT_FAILURE); } sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("[ipc_init] SEM_MUTEX = %d/n", sem_val); /* available read resources */ semun.val = 0; if(semctl(semid, SEM_RD, SETVAL, semun) == -1) { perror("[ipc_init] semctl failed"); exit(EXIT_FAILURE); } sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("[ipc_init] SEM_RD = %d/n", sem_val); /* struct sembuf sem_b; sem_b.sem_num = SEM_RD; sem_b.sem_op = -SHMLEN; sem_b.sem_flg = SEM_UNDO; if(semop(semid, &sem_b, 1) == -1) { perror("[sem_p] p failed"); return 0; } sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("[ipc_init] SEM_RD = %d/n", sem_val); */ /* available write resources */ semun.val = SHMLEN; if(semctl(semid, SEM_WR, SETVAL, semun) == -1) { perror("[ipc_init] semctl failed"); exit(EXIT_FAILURE); } sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("[ipc_init] SEM_WR = %d/n", sem_val); /* init the shared mem parameters */ shm = shmat(shmid, (void *)NULL, 0); if(shm == (void *) -1) { perror("[ipc_init] shmat failed"); exit(EXIT_FAILURE); } printf("[ipc_init] shm %d attached at %X/n", shmid, (int)shm); shm_st = (SHM_ST *)shm; shm_st->semid = semid; printf("[ipc_init] shm_st->semid = %d/n", shm_st->semid); shm_st->rd_ptr = 0; shm_st->wr_ptr = 0; } int sem_p(int semid, short semnum) { struct sembuf sem_b; sem_b.sem_num = semnum; sem_b.sem_op = -1; sem_b.sem_flg = SEM_UNDO; if(semop(semid, &sem_b, 1) == -1) { perror("[sem_p] p failed"); return 0; } return 1; } int sem_v(int semid, short semnum) { struct sembuf sem_b; sem_b.sem_num = semnum; sem_b.sem_op = 1; sem_b.sem_flg = SEM_UNDO; if(semop(semid, &sem_b, 1) == -1) { perror("[sem_v] v failed"); return 0; } return 1; } /************************************* * consumer * *************************************/ void ue_proc(int shmid) { void * shm = (void *)NULL; SHM_ST * shm_st; PACK pack; int sem_val, semid; shm = shmat(shmid, (void *)NULL, 0); if(shm == (void *) -1) { perror("[ue_proc] shmat failed"); exit(EXIT_FAILURE); } shm_st = (SHM_ST *)shm; semid = shm_st->semid; printf("[ue_proc] shm %d attached at %X/n", shmid, (int)shm); printf("[ue_proc] semid = %d/n", semid); while(1) { #ifdef DEBUG printf("[ue_proc] (before RD) "); sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("SEM_MUTEX = %d ", sem_val); sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("SEM_RD = %d ", sem_val); sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("SEM_WR = %d/n", sem_val); #endif if(!sem_p(semid, SEM_RD)) { exit(EXIT_FAILURE); } if(!sem_p(semid, SEM_MUTEX)) { exit(EXIT_FAILURE); } pack.length = shm_st->unit[shm_st->rd_ptr].pack_len; pack.addr = malloc(pack.length); memcpy(pack.addr, shm_st->unit[shm_st->rd_ptr].pack_cont, pack.length); printf("[ue_proc] r: %x %d/n", *pack.addr, pack.length); fflush(stdout); free(pack.addr); shm_st->rd_ptr++; if(shm_st->rd_ptr == SHMLEN) { shm_st->rd_ptr = 0; } #ifdef DEBUG printf("[ue_proc] (durning RD) "); sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("SEM_MUTEX = %d ", sem_val); sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("SEM_RD = %d ", sem_val); sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("SEM_WR = %d/n", sem_val); #endif if(!sem_v(semid, SEM_MUTEX)) { exit(EXIT_FAILURE); } if(!sem_v(semid, SEM_WR)) { exit(EXIT_FAILURE); } #ifdef DEBUG printf("[ue_proc] (after RD) "); sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("SEM_MUTEX = %d ", sem_val); sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("SEM_RD = %d ", sem_val); sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("SEM_WR = %d/n", sem_val); #endif } if(shmdt(shm) == -1) { fprintf(stderr, "[ue_proc] shmdt failed/n"); exit(EXIT_FAILURE); } if(shmctl(shmid, IPC_RMID, 0) == -1) { fprintf(stderr, "[ue_proc] shmctl(IPC_RMID) failed/n"); exit(EXIT_FAILURE); } } /************************************* * producer * *************************************/ void enb_proc(int shmid) { void * shm = (void *)NULL; SHM_ST * shm_st; PACK pack; int sem_val, semid; static int i = 1001; shm = shmat(shmid, (void *)NULL, 0); if(shm == (void *) -1) { perror("[enb_proc] shmat failed"); exit(EXIT_FAILURE); } shm_st = (SHM_ST *)shm; semid = shm_st->semid; printf("[enb_proc] shm %d attached at %X/n", shmid, (int)shm); printf("[enb_proc] semid = %d/n", semid); while(1) { #ifdef DEBUG printf("[enb_proc] (before WR) "); sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("SEM_MUTEX = %d ", sem_val); sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("SEM_RD = %d ", sem_val); sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("SEM_WR = %d/n", sem_val); #endif if(!sem_p(semid, SEM_WR)) { exit(EXIT_FAILURE); } if(!sem_p(semid, SEM_MUTEX)) { exit(EXIT_FAILURE); } pack.length = i; pack.addr = malloc(pack.length); memset(pack.addr, i % 3, pack.length); printf("[enb_proc] w: %x %d/n", *pack.addr, pack.length); fflush(stdout); shm_st->unit[shm_st->wr_ptr].pack_len = pack.length; memcpy(shm_st->unit[shm_st->wr_ptr].pack_cont, pack.addr, pack.length); shm_st->wr_ptr++; if(shm_st->wr_ptr == SHMLEN) { shm_st->wr_ptr = 0; } free(pack.addr); i++; #ifdef DEBUG printf("[enb_proc] (durning WR) "); sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("SEM_MUTEX = %d ", sem_val); sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("SEM_RD = %d ", sem_val); sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("SEM_WR = %d/n", sem_val); #endif if(!sem_v(semid, SEM_MUTEX)) { exit(EXIT_FAILURE); } if(!sem_v(semid, SEM_RD)) { exit(EXIT_FAILURE); } #ifdef DEBUG printf("[enb_proc] (after WR) "); sem_val = semctl(semid, SEM_MUTEX, GETVAL, NULL); printf("SEM_MUTEX = %d ", sem_val); sem_val = semctl(semid, SEM_RD, GETVAL, NULL); printf("SEM_RD = %d ", sem_val); sem_val = semctl(semid, SEM_WR, GETVAL, NULL); printf("SEM_WR = %d/n", sem_val); #endif } if(shmdt(shm) == -1) { perror("[enb_proc] shmdt failed"); exit(EXIT_FAILURE); } } int main() { pid_t pid; int shmid; shmid = shmget((key_t)IPC_PRIVATE, sizeof(SHM_ST), 0666 | IPC_CREAT); if(shmid == -1) { perror("[main] shmget failed"); exit(EXIT_FAILURE); } srand((unsigned int)getpid()); pid = fork(); switch(pid) { case -1: perror("[main]fork failed/n"); break; case 0: // producer sleep(1); printf("==== eNB ====/n"); enb_proc(shmid); break; default: // consumer printf("==== UE ====/n"); ipc_init(shmid); ue_proc(shmid); break; } exit(EXIT_SUCCESS); }  

 

执行:

 

opal@meadfield:~/work$ gcc -o proc -lpthread proc.c

opal@meadfield:~/work$ ./proc

 

打印结果:

 

==== UE ====

[ipc_init] semid = 393222

[ipc_init] SEM_MUTEX = 1

[ipc_init] SEM_RD = 0

[ipc_init] SEM_WR = 7

[ipc_init] shm 4784156 attached at B80C0000

[ipc_init] shm_st->semid = 393222

[ue_proc] shm 4784156 attached at B80B8000

[ue_proc] semid = 393222

[ue_proc] (before RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

==== eNB ====

[enb_proc] shm 4784156 attached at B80C0000

[enb_proc] semid = 393222

[enb_proc] (before WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] w: 2 1001

[enb_proc] (durning WR) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[enb_proc] (after WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 6

[enb_proc] (before WR) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[ue_proc]  r: 2 1001

[ue_proc] (durning RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 5

[ue_proc] (after RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[ue_proc] (before RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[enb_proc] w: 0 1002

[enb_proc] (durning WR) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[enb_proc] (after WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 6

[ue_proc]  r: 0 1002

[ue_proc] (durning RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[ue_proc] (after RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[ue_proc] (before RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] (before WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] w: 1 1003

[enb_proc] (durning WR) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[enb_proc] (after WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 6

[ue_proc]  r: 1 1003

[ue_proc] (durning RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[ue_proc] (after RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[ue_proc] (before RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] (before WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] w: 2 1004

[enb_proc] (durning WR) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[enb_proc] (after WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 6

[ue_proc]  r: 2 1004

[ue_proc] (durning RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[ue_proc] (after RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[ue_proc] (before RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] (before WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] w: 0 1005

[enb_proc] (durning WR) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[enb_proc] (after WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 6

[ue_proc]  r: 0 1005

[ue_proc] (durning RD) SEM_MUTEX = 0 SEM_RD = 0 SEM_WR = 6

[ue_proc] (after RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[ue_proc] (before RD) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

[enb_proc] (before WR) SEM_MUTEX = 1 SEM_RD = 0 SEM_WR = 7

你可能感兴趣的:(Linux)