进程间通信4信号量

/****************************************************************************
*信号量,信号量是指多个进程同时执行的时候,同一段代码同一时间段只能由一个进程来执行
*及pv操作,(一个进程执行到临界区会执行p操作是否是可执行的,如果不可执行就阻塞直到可执行)
*          执行完这段代码之后在执行v操作,可以让别的进程执行这段代码 
*     pv这个区间被称为临界区。
*               p操作, 如果信号量的值 > 0,    则把该信号量减1
*               如果信号量的值  ==0,  则挂起该进程。
*               
*     V操作:  如果有进程因该信号量而被挂起,则恢复该进程运行
*             如果没有进程因该信号量而挂起,则把该信号量加1
*               
*    注意:P操作、V操作都是原子操作,即其在执行时,不会被中断。
******************************************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)						   
#else
    union semun {
    
    
        int val;                             
        struct semid_ds *buf;    
        unsigned short int *array; 
        struct seminfo *__buf;  
    };
#endif     

static sem_initial(int semid) 
{
    
    
	int ret;
	
	union semun semun;//控制信号量的结构体
	semun.val = 1;
	/*
	@1.信号量的标识符
	@2.信号量组中的编号,如果只有一个信号量,则取0
	@3.cmd 命令 把信号量初始化为指定的值,具体的值由第4个参数确定
	@4.自定义结构体*/
	ret = semctl(semid, 0, SETVAL, semun);//对信号量进行控制(初始化)
	if (ret == -1) {
    
    
		fprintf(stderr, "semctl failed!\n");
	}
	
	return ret;
}

static int  sem_p(int semid)//执行p操作
{
    
    
	int ret;
	
	struct sembuf sembuf;//信号量传参的结构体
	sembuf.sem_op = -1;//执行p操作将这个值赋值为-1 表示其他的进程不能执行
	
	sembuf.sem_num = 0;//信号量组中的编号(即指定对哪个信号量操作)
                         //semget实际是获取一组信号量
                         //如果只获取了一个信号量,则该成员取0
	sembuf.sem_flg = SEM_UNDO;// SEM_UNDO : 如果进程在终止时,没有释放信号量
                           // 如果不设置指定标志,应该设置为0                                 
                           //则,自动释放该信号量



	/*@1.信号量标识符(句柄)
      @2.sembuf结构体
      @3.表示第二个参数sembuf所表示的数组的大小,即表示有几个struct sembuf*/
	ret = semop(semid, &sembuf, 1);	
	if (ret == -1) {
    
    
		fprintf(stderr, "sem_p failed!\n");
	}
	
	return ret;
}

static int  sem_v(int semid)//执行v操作
{
    
    
	int ret;
	
	struct sembuf sembuf;//信号量传参的结构体
	sembuf.sem_op = 1;//执行v操作就赋值为1表示其他进程可执行
	sembuf.sem_num = 0;//信号量组中的编号(即指定对哪个信号量操作)
                         //semget实际是获取一组信号量
                         //如果只获取了一个信号量,则该成员取0
	sembuf.sem_flg = SEM_UNDO;// SEM_UNDO : 如果进程在终止时,没有释放信号量
                           // 如果不设置指定标志,应该设置为0                                 
                           //则,自动释放该信号量


    /*@1.信号量标识符(句柄)
      @2.sembuf结构体
      @3.表示第二个参数sembuf所表示的数组的大小,即表示有几个struct sembuf*/
	ret = semop(semid, &sembuf, 1);	//改变信号量的值,即对信号量执行P操作、或V操作。
	if (ret == -1) {
    
    
		fprintf(stderr, "sem_v failed!\n");
	}
	
	return ret;
}

int main(int argc, char* argv[]) 
{
    
    
	int i;
	int ret;
	int semid;

	/* 获取信号量,获取一个已存在的、或创建一个新的信号量量,返回该信号量的标识符
	@1.key, 键值,该键值对应一个唯一的信号量。
	@2.需要的信号量数目,一般取1
	@3.与共享内存的sem_flags类似。IPC_CREAT, 如果该信号量未存在,
	则创建该信号量如果该信号量已存在,也   不发送错误。0666所有用户可访问 */
	semid = semget((key_t)1234, 1, 0666 | IPC_CREAT);//这个程序编译完,
	//同时跑两个客户端即可看到效果,有点像互斥锁的意思
	if (semid == -1) {
    
    
		printf("semget failed!\n");
		exit(1);
	}

	/* 初始化信号量 */
	
	if (argc > 1) {
    
    
		ret = sem_initial(semid);
		if (ret == -1) {
    
    
			exit(1);
		}
	}
    
	for (i=0; i<5; i++) {
    
    

		if (sem_p(semid) == -1) //取得执行权
		{
    
    
			exit(1);
		}
		
		/* 模拟临界区----begin */
		//执行到这里别的进程在执行这段代码会挂起(阻塞)
		printf("Process(%d) In\n", getpid());		
		sleep(1);
		printf("Process(%d) Out\n", getpid());
        /* 模拟临界区----end */ 

		if (sem_v(semid) == -1) //放弃执行权
		{
    
    
			exit(1);
		}
			  
		sleep(1);
	}

    /* 删除信号量 */
	   
	return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_45743563/article/details/113816374