Linux高级进程间通信:信号量

本文介绍了一个使用信号量实现进程间同步的经典案例。父进程创建三个子进程,并通过信号量机制确保它们互斥地访问临界区,避免了资源冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

父进程产生三个子进程,每一个都使用p()和v()来阻止其他进程在同一时刻执行一段关键区域。

 

 

pv.h:

/*semaphore exapmle header file */
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>

#define SEMPERM   0600
#define  FALSE     0
#define   TRUE    1
/* use typedef so we can do like this:{semun mymun;} */
/*to define a union */
typedef union _semun{    
	int val;    
	struct semid_ds *buf;   
	ushort *array;
	}semun;
	


 

initsem.c:

#include "pv.h"
/*initsem----semaphore initialization */
int initsem(key_t semkey)
{  
  int status=0,semid;    
  if((semid=semget(semkey,1,SEMPERM|IPC_CREAT|IPC_EXCL))==-1)    
	{       
	  if(errno==EEXIST)//if exist,get the semkey      
	   	{            
		   semid=semget(semkey,1,0);      
	   	}  
	} 
	/*if create succeeded*/  
   else 
	{      
		semun arg;//define a semun union    
		arg.val=1;//1 sem    
		status=semctl(semid,0,SETVAL,arg);//the index begin from 0表示只有一个信号量  
	}   

	if(semid==-1||status==-1)   
		{      
			perror("initsem failed");     
		    return (-1);  
		}   

	/*all OK */  
	return (semid);
}


 

 

 

p.c:

 

/*p.c---semaphore p operation--wait*/
#include "pv.h"
int p(int semid)
{    
	struct sembuf p_buf;   
	p_buf.sem_num=0;	//include a sem   
	p_buf.sem_op=-1;    //p,wait  
	p_buf.sem_flg=SEM_UNDO;//undo表示进程退出时抵消对信号量的影响,因此所有进程退出后信号值的初值还是一样的    
	if(semop(semid,&p_buf,1)==-1)//1 means??only have a struct?   
	{   
		perror("P(semid) failed");      
		exit (1);  
	}   
	return (0);
}


 

 

v.c:

 

/*v.c----semaphore v operation--signal */
#include "pv.h"

int v(int semid)
{   
	struct sembuf v_buf;   
	v_buf.sem_num=0;//1 sem   
	v_buf.sem_op=1;//v signal  
	v_buf.sem_flg=SEM_UNDO;//undo  
	if(semop(semid,&v_buf,1)==-1)   
	{      
		perror("v(semid)failed");   
		exit (1);  
		}   
	return (0);
}


 

 

testsem.c:

 

/* testsem.c----test semaphore routines */
#include "pv.h"
#include<stdio.h>

void handlesem(key_t skey);

int main(void)
{   
	key_t semkey=0x200;    
	int i;  
	for(i=0;i<3;i++) //create three process  
	{       
		if(fork()==0)//child    
	    {          
			handlesem(semkey);   
		}   
	}   
	return 0;
}

void handlesem(key_t skey)
{   
	int semid;  
	pid_t pid=getpid();//get pid 
	if((semid=initsem(skey))<0)//initialize sem   
	{      
	 exit (1);  
	}   
	printf("/nprocess %d before critical section /n",pid);    
	p(semid);  
	printf("process %d in critical section /n",pid);  
	/* do something when wait succeeded  
	*     *     *     *     *     */  
	sleep(5);   
	printf("process %d leaving critical section/n",pid);  
	v(semid);
	printf("process %d exiting /n",pid); 
	exit (0);
}


 

 

运行结果:
jiang@jiang-linux:~/unixprog/2011324$ gcc initsem.c p.c v.c testsem.c -o testsem.o;./testsem.o
process 2731 before critical section
process 2731 in critical section

process 2732 before critical section

process 2733 before critical section
process 2731 leaving critical section
process 2731 exiting
process 2732 in critical section
process 2732 leaving critical section
process 2732 exiting
process 2733 in critical section
process 2733 leaving critical section
process 2733 exiting