红联Linux门户
Linux帮助

Linux下使用信号量来进行进程间通信

发布时间:2015-09-21 10:44:32来源:linux网站作者:飘雪的冬夜

贴一篇代码,我们操作系统老师布置的作业,由单信号量,改为一个信号集中多信号量。水平有限,写的不好。


#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 
#include<sys/mman.h>   //提供了共享内存的相关操作  
#include<fcntl.h> 
#include<sys/stat.h> 
 
union semun { 
int val; 
struct semid_ds *buf; 
unsigned short *array; 
} arg; 
 
//生成信号量 
//信号量创建 
//第一个:同步信号量,表示先后顺序,必须有空间才能生产 
//第二个:同步信号量,表示先后顺序,必须有产品才能消费 
//第三个:互斥信号量,生产者和每个消费者不能同时进入缓冲区 
int sem_creat(key_t key) 

union semun sem[3]; 
int semid; 
sem[0].val = 5;//最多5个产品 
sem[1].val=0; 
sem[2].val=1; 
semid = semget(key, 3, IPC_CREAT|0666);//三个信号量,空、满、进入缓冲区。 
if (-1 == semid) 

printf("create semaphore error\n"); 
exit(-1); 

semctl(semid, 0, SETVAL, sem[0]);//初始信号量集中的第一个信号量 
semctl(semid,1,SETVAL,sem[1]);//第二个 
semctl(semid,2,SETVAL,sem[2]);//第三个 
return semid; 

 
//删除信号量 
void del_sem(int semid) 

union semun sem; 
sem.val = 0; 
semctl(semid, 0, IPC_RMID, sem); 
semctl(semid, 1, IPC_RMID, sem); 
semctl(semid, 2, IPC_RMID, sem); 

 
//p操作 
int p(int semid,int semIndex) 

struct sembuf sops={semIndex, -1, SEM_UNDO};//这里的“semIndex”是信号量集里的信号量序号 
return (semop(semid, &sops, 1)); 

//v操作 
int v(int semid,int semIndex) 

struct sembuf sops={semIndex, +1, SEM_UNDO};//这里的“semIndex”是信号量集里的信号量序号 
return (semop(semid, &sops, 1)); 

 
int buffer; 
int Num=5; 
int *pData; 
int value_read = 0, value_write = 0; 
int full, empty,all; 
int start=0,end=0; 
 
void producer(key_t); 
void consumer(int); 
 
int main(void) 
{
key_t keyFull, keyEmpty,key; 
int fd; 
pid_t pid; 
void *ptr;   //指向共享内存的指针
 
/* shm_open是一个POSIX函数,用来打开或创建一个与“/shm”关联的共享内存区 */ 
if((fd = shm_open("/shm", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1)//shmget(...) 

printf("shm_open error\n"); /* 出错提示 */ 

if(ftruncate(fd, sizeof(int)*5) == -1) /* 截短共享内存的长度到我们所需要的长度 */ 

printf("ftruncate error\n"); 

if((ptr = mmap(0, sizeof(int)*5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) /* 将共享内存映射到进程地址空间 */ 

printf("mmap error"); 
}

pData = (int *)ptr; 
//keyFull = ftok("/", 0); 
//keyEmpty = ftok("/", 1); 
key=ftok("/", 0); 
//full = sem_creat(keyFull, 0); 
//empty = sem_creat(keyEmpty, 1); 
all=sem_creat(key); 
switch(pid = fork()) 

case -1: /* 生成子进程失败 */
break; 
case 0: /* 子进程 */ 
//producer(keyFull, keyEmpty); /* 子进程是生产者 */ 
producer(key); 
sleep(2);
break; 
default: 
//consumer(full, empty); /* 父进程是消费者 */ 
consumer(all); 
break; 

wait(0); 
shm_unlink("/shm"); /* 删除共享内存区,程序中基本上保证了子进程先退出,因此父进程中无wait操作且这部操作放在父进程这里 */ 
//shmctl(shmid,IPC_RMID,&buf); 
//del_sem(semid); 
return 0; 

 
/* 生产者写5次后退出 */ 
//void producer(key_t keyFull, key_t keyEmpty) 
void producer(key_t key) 

//full = semget(keyFull, 3, 0); 
//empty = semget(keyEmpty, 3, 0); 
all=semget(key,3,0); 
 
while(value_write < 10) /* 退出条件判定 */ 

//printf("Prepare Write\n"); 
printf("准备写\n"); 
//printf("empty Write P1 : %d\n", semctl(empty, 0, GETVAL, 0)); 
p(all,0); //判断是否有空
p(all,2);//操作缓冲区 
//printf("empty Write P2 : %d\n", semctl(empty, 0, GETVAL, 0));  
value_write++;  
*(pData+start%Num) = value_write; 
//printf("Write : %5d\n", *(pData+start%Num)); 
printf("写 : %5d\n", *(pData+start%Num));  
start++;  
//printf("full Write V1 : %d\n", semctl(full, 0, GETVAL, 0));
v(all,2);//释放缓冲区 
v(all,1); //通知消费者 
//printf("full Write V2 : %d\n", semctl(full, 0, GETVAL, 0)); 
//printf("Write Finish\n"); 
printf("写结束\n"); 
//sleep(3); 


 
/* 消费者读5次后退出 */ 
//void consumer(int full, int empty) 
void consumer(int all) 

while(value_read < 10) /* 退出条件判定 */ 
{  
//printf("  Prepare Read\n"); 
printf("准备读\n"); 
//printf("  full Read P1 : %d\n", semctl(full, 0, GETVAL, 0)); 
p(all,1);//判断是否有产品 
p(all,2); //操作缓冲区 
//printf("  full Read P1 : %d\n", semctl(full, 0, GETVAL, 0));
//printf("  Read : %5d\n", *(pData+end%Num));
printf("读 : %5d\n", *(pData+end%Num)); 
//printf("  empty Read V1 : %d\n", semctl(empty, 0, GETVAL, 0)); 
//printf("  empty Read V1 : %d\n", semctl(empty, 0, GETVAL, 0)); 
//value_read ++; 
//printf("  Read Finish\n"); 
printf("读结束\n"); 
if(*(pData+end%Num) == 10) 
exit(0); 
end++; 
v(all,2);//释放缓冲区 
v(all,0);//通知生产者 
//sleep(1); 


//gcc -lrt p.c (-o 目标文件名) 
//./a.out


Linux进程间的同步方法的优缺点比较:http://www.linuxdiyf.com/linux/11023.html

Linux下几种进程间通信详细分析:http://www.linuxdiyf.com/linux/533.html