歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux 進程間通信(system v 信號燈+ posix共享內存)實例

Linux 進程間通信(system v 信號燈+ posix共享內存)實例

日期:2017/2/28 16:05:19   编辑:Linux教程

mmap()系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程可以向訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作。

注:實際上,mmap()系統調用並不是完全為了用於共享內存而設計的。它本身提供了不同於一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件的操作。而Posix或系統V的共享內存IPC則純粹用於共享目的,當然mmap()實現共享內存也是其主要應用之一。


編譯:gcc -o consumer consumer.c -lrt

gcc -o producer producer.c -lrt


/*
*
* Filename: producer.c
*
* Description: 生產者進程
*
* Version: 1.0
* Created: 09/30/2011 04:52:23 PM
* Revision: none
* Compiler: gcc(g++)
*
* Author: |Zhenghe Zhang|, |[email protected]|
* Company: |Shenzhen XXX Technology Co., Ltd.|
*
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/mman.h>

#define MAXSHM 5 //定義緩沖區數組的下標變量個數

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;
};

int main()
{
int fd;
key_t semkey;

int shmid;
char *addr_c;

/*定義信號燈集,該信號燈集包含3個信號量 fullid, emptyid, mutexid */
int semid;

/*共享文件*/
const char *file = "/shmipcx";

fd = shm_open(file, O_CREAT | O_RDWR | O_TRUNC, 0666);
if(fd == -1)
{
perror("shm_open");
exit(1);
}

/*ftruncate()會將參數fd指定的文件大小改為參數length指定的大小。*/
/*參數fd為已打開的文件描述詞,而且必須是以寫入模式打開的文件。*/
/*如果原來的文件大小比參數length大,則超過的部分會被刪去。*/
if(ftruncate(fd, sizeof(char) * MAXSHM) == -1)
{
perror("ftruncate");
exit(1);
}

/*mmap()用來將某個文件內容映射到內存中,對該內存區域的存取即是直接對該文件內容的讀寫。*/
/*參數start指向欲對應的內存起始地址,通常設為NULL,代表讓系統自動選定地址,對應成功後該地址會返回。*/
/*參數length代表將文件中多大的部分對應到內存。*/
addr_c = (char*)mmap(NULL, sizeof(char) * MAXSHM, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(*((int*)addr_c) == -1)
{
perror("mmap");
exit(1);
}

/* 定義信號量數據結構 */
struct sembuf P,V;
union semun arg1, arg2, arg3;

semkey = ftok("/home/zhang/shmipcy", 10001);
if(semkey == -1)
{
perror("ftok");
exit(1);
}

/* 創建信號燈集 */
semid = semget(semkey, 3, IPC_CREAT | 0666); //如果創建新集合(一般在服務器進程中), 則必須指定nsems
if(semid < 0)
{
perror("semget semid");
exit(0);
}

/*初始化信號燈集中的信號量 */
arg1.val = 0; //初始時緩沖區中無數據 (fullid, 緩沖區滿信號量)
if(semctl(semid, 0, SETVAL, arg1) == -1)
{
perror("semctl setval error");
exit(1);
}

arg2.val = MAXSHM; //初始時緩沖區中有5個空閒的數組元素 (emptyid, 緩沖區空信號量)
if(semctl(semid, 1, SETVAL, arg2) == -1)
{
perror("semctl setval error");
exit(1);
}

arg3.val = 1; //初始時互斥信號為1,允許一個進程進入 (mutexid, 互斥信號量)
if(semctl(semid, 2, SETVAL, arg3) == -1)
{
perror("semctl setval error");
exit(1);
}

/* 初始化 P, V操作 */
P.sem_num = 0;
P.sem_op = -1;
P.sem_flg = SEM_UNDO;
V.sem_num = 0;
V.sem_op = 1;
V.sem_flg = SEM_UNDO;

int i = 0;

while(i < 10)
{
P.sem_num = 1; //設置操作信號量emptyid
semop(semid, &P, 1); //對 emptyid執行P操作

P.sem_num = 2; //設置操作信號量mutexid
semop(semid, &P, 1); //對 mutexid執行 P操作

addr_c[i] = i + 'a';
printf("***addr_c[%d] = %c\n", i, addr_c[i]);

V.sem_num = 2; //設置操作信號量mutexid
semop(semid, &V, 1); //對mutexid執行 V 操作

V.sem_num = 0; //設置操作信號量fullid
semop(semid, &V, 1); //對fullid執行 V 操作

i++;
sleep(1);
}

sleep(20); //等待消費者進程退出

/*munmap()用來取消參數start所指的映射內存起始地址,參數length則是欲取消的內存大小。*/
/*當進程結束或利用exec相關函數來執行其他程序時,映射內存會自動解除,但關閉對應的文件描述詞時不會解除映射。*/
if(munmap(addr_c, sizeof(char) * MAXSHM) == -1)
{
perror("munmap");
exit(1);
}

if(shm_unlink(file) == -1)
{
perror("shm_unlink");
exit(1);
}

/* 撤消信號集 */
if(semctl(semid, 0, IPC_RMID, 0) == -1)
{
perror("semctl");
exit(1);
}

return 0;
}

/*
*
* Filename: consumer.c
*
* Description: 消費者進程
*
* Version: 1.0
* Created: 09/30/2011 04:52:23 PM
* Revision: none
* Compiler: gcc(g++)
*
* Author: |Zhenghe Zhang|, |[email protected]|
* Company: |Shenzhen XXX Technology Co., Ltd.|
*
*/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/mman.h>

#define MAXSHM 5 //定義緩沖區數組的下標變量個數


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 */ //test!!
void *__pad;
};

int main()
{
int fd;
key_t semkey;

int shmid;
char *addr_c;

/* 定義信號燈集,該信號燈集包含3個信號量 fullid, emptyid, mutexid */
int semid;

/*共享文件*/
const char *file = "/shmipcx";

fd = shm_open(file, O_CREAT | O_RDWR, 0666);
if(fd == -1)
{
perror("shm_open");
exit(1);
}

if(ftruncate(fd, sizeof(char) * MAXSHM) == -1)
{
perror("ftruncate");
exit(1);
}

addr_c = (char*)mmap(NULL, sizeof(char) * MAXSHM, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(*((int*)addr_c) == -1)
{
perror("mmap");
exit(1);
}

/* 定義信號量數據結構 */
struct sembuf P, V;
//union semun arg1, arg2, arg3;

semkey = ftok("/home/zhang/shmipcy", 10001);
if(semkey == -1)
{
perror("ftok");
exit(1);
}

/* 創建信號燈集 */
semid = semget(semkey, 0, IPC_EXCL | 0666); //如果引用一個現存的集合(一個客戶進程), 則將nsems指定為0
if(semid < 0)
{
perror("semget semid");
exit(0);
}

/* 初始化 P V操作 */
P.sem_num = 0;
P.sem_op = -1;
P.sem_flg = SEM_UNDO;
V.sem_num = 0;
V.sem_op = 1;
V.sem_flg = SEM_UNDO;

int i = 0;

while(i < 10)
{
P.sem_num = 0;
semop(semid, &P, 1); //對fullid執行 P 操作

P.sem_num = 2;
semop(semid, &P, 1); //對mutexid執行 P 操作

printf("***addr_c[%d] = %c\n", i, addr_c[i]);

V.sem_num = 2;
semop(semid, &V, 1); //對mutexid執行 V 操作

V.sem_num = 1;
semop(semid, &V, 1); //對empty執行 V 操作

i++;
sleep(2);
}

if(munmap(addr_c, sizeof(char) * MAXSHM) == -1)
{
perror("munmap");
exit(1);
}

if(shm_unlink(file) == -1)
{
perror("shm_unlink");
exit(1);
}

return 0;
}
Copyright © Linux教程網 All Rights Reserved