一、信号量:(数据操作锁)控制进程间互斥、同步等,协调多个程序同时访问一个共享资源。

    工作原理:信号量只能有两种操作等待和操作,即:P V操作,必须是原子操作。

              P(sv):如果 sv 的值大于零就减一;如果它的值为零,就挂起;

              V(sv):如果有被挂起的,恢复运行,如果没有就加一。

二、函数原型:

    int semget(key_t key, int nsems,int semflg);

    int semop(int semid,struct sembuf *sops,size_t nsops);

    int semctl(int semid, int semnum, int cmd, ...);

    /*    

     *    semid:信号量集的标识符;    semnum:第几个信号量;

     *    cmd:需要执行的命令,根据命令的不同,函数有三个或四个参数(union)

     */

     cmd:IPC_RMID,立即删除信号集,唤醒被阻塞的进程;

     cmd:SETVAL,设置信号量集中的一个单独的信号量的值。

     cmd:GETALL用于读取信号量集中的所有信号量的值。

     union semun

     {

         int val;

         struct semid_ds *buf;

         unsigned short *array;

         struct seminfo *_buf;

      };//用户需自己定义声明


      struct sembuf

      {

          unsigned short sem_num;

          short sem_op;

          short sem_flg;

      };


三、代码实现:

//sem.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/ipc.h>
#include<string.h>
#include<errno.h>

#define _PATH_ "."
#define _ID_ 0x666

static int op_sem(int sem_id, int op, int which);
int creat_sem(int _sem_num);
int get_sem();
int init_sem(int _sem_id, int _which);
int sem_p(int _sem_id, int _which);
int sem_v(int _sem_id, int _which);
int destroy_sem(int _sem_id);

union semun
{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *__buf;
};

//sem.c

#include"sem.h"

int creat_sem(int snum)
{
	int flags = IPC_CREAT|IPC_EXCL|0666;
	key_t key = ftok(_PATH_, _ID_);
	if(key < 0)
	{
		perror("ftok");
		return -1;
	}
	return semget(key, snum, flags);
}

int get_sem()
{
	key_t key = ftok(_PATH_, _ID_);
	if(key < 0)
	{
		perror("ftok");
		return -1;
	}
	return semget(key, 0, IPC_CREAT);
}

static int op_sem(int sem_id, int op, int which)
{
	struct sembuf sem;
	memset(&sem, '\0',sizeof(sem));
	sem.sem_num = which;
	sem.sem_op = op;
	sem.sem_flg = 0;
	if(semop(sem_id, &sem, 1) < 0)
	{
		perror("semop");
		return -1;
	}
	return 0;
}

int sem_p(int sem_id, int which)
{
	return op_sem(sem_id, -1, which);
}

int sem_v(int sem_id, int which)
{
	return op_sem(sem_id, 1, which);
}

int init_sem(int sem_id, int which)
{
	union semun _semun;
	_semun.val = 1;
	if(semctl(sem_id, SETVAL, which, _semun) < 0)
	{
		perror("semctl");
		return -1;
	}
	return 0;
}

int destroy_sem(int sem_id)
{
	if(semctl(sem_id, 0, IPC_RMID, NULL) < 0)
	{
		perror("semctl");
		return -1;
	}
	return 0;
}

//test.c

#include"sem.h"

int main()
{
	int sem_id = creat_sem(1);
	if(sem_id < 0)
	{
		printf("creat_sem error");
		return -1;
	}
	init_sem(sem_id, 0);
	pid_t id  = fork();
	if(id < 0)
	{
		perror("fork");
		return -1;
	}
	else if(id == 0)
	{
		int sem_id = get_sem(1);
		while(1)
		{
			sem_p(sem_id, 0);	
			printf("A");
			sleep(1);
			fflush(stdout);
			printf("A");
			sleep(2);
			fflush(stdout);
			sem_v(sem_id, 0);
		}
	}
	else
	{
		while(1)
		{
			sem_p(sem_id, 0);	
			printf("B");
			fflush(stdout);
			printf("B");
			sleep(1);
			fflush(stdout);
			sem_v(sem_id, 0);
		}
		waitpid(id, NULL, 0);
		destroy_sem(sem_id);
	}
	return 0;
}

四、实现结果:


使用信号量之前

wKiom1cWPxeDYp5GAABSILVLxwI470.png

使用信号量之后

wKiom1cWP27R28YxAABlnSP5zuI503.png