信号量是一个计数器。可以用于多进程也可以用于多线程,主要用于共享数据的同步访问。

如果受保护的资源是可用的,那么信号量的值为正数,如果受保护的资源现在不可用,那么信号量的值为0。

请求访问保护资源(P操作):

要访问受保护的资源的进程或者线程试图对信号量的值减1,如果信号量的值现在不可用,即信号量为0,减1操作将被阻塞(休眠),直到信号量大于0时,才会得以继续执行。

释放保护资源(V操作):

要释放受保护的资源时,信号量的值将会加1,此时信号量的值大于0,其他请求该资源被信号量阻塞的线程或者进程将被唤醒。

 

总之,信号量为0(信号量不能小于0),无可用资源,信号量大于0,有可用资源。

释放资源,则将信号量加1,请求资源,则信号量减1。

初始化:

控制单个资源,信号量初始值为1,N个资源,初始值为N

 

 

 

1.信号量的创建

       #include <sys/types.h>

       #include <sys/ipc.h>

       #include <sys/sem.h>

 

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

 

(1)key从ftok函数获取

(2)nsems信号量集的个数,换句话来说,semget创建的信号量集id,可以控制nsems个资源的访问和释放。

(3)semflg是信号量的权限设置,如果信号量不存在,semflg要跟IPC_CREAT相与,否则,要跟IPC_PRIVATE相与,如果设置权限所有人都能访问,semflg设置为0666|IPC_CREAT或者0666|IPC_PRIVATE。

(4)函数返回值为信号量集id,如为-1,则创建失败。

 

 

 

2.信号量的资源操作(P和V)

#include <sys/types.h>

       #include <sys/ipc.h>

       #include <sys/sem.h>

 

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

 

(1)semid是信号量集id

(2)struct sembuf 结构体定义有如下成员:

 unsigned short sem_num;  /* semaphore number */

   short   sem_op;   /* semaphore operation */

   short   sem_flg;  /* operation flags */

其中sem_num是要操作的信号量集中的资源序号,比如有10个资源,序号为(0,1,2,...,9),

 

sem_op的值为正数、负数,0,三种。

设置为正数表示释放资源操作(V操作)

设置为负数表示要请求资源访问的操作(P操作)

设置0表示等待可用资源为0。

(3)sem_flg设置为IPC_NOWAIT或SEM_UNDO

 

4.信号量的删除

       #include <sys/types.h>

       #include <sys/ipc.h>

       #include <sys/sem.h>

 

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

 

设置cmd为IPC_RMID即为删除信号量

其中semnum可以忽视

 

semctl( semid,0,IPC_RMID);

 

 

 

以下代码设置一个信号量管理多线程中的5个临界资源的同步访问



#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  
#include <sys/ipc.h> 
#include <sys/sem.h>
#include <sys/msg.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>


#define SemKey 6541
#define SemNum 5
#define SemOpNegative (-1)
#define SemOpPositive 1
#define SemOpZero (0)
static int  gs_nSemid = -1; 

int Sem_init(int *pnSemId,int nSemNum)
{
	key_t key=-1;
	int nSemid = -1;
	
	if(pnSemId == NULL ||
		nSemNum <= 0)
	{
		printf("\n  param error [%s %d]\n",__FUNCTION__,__LINE__);
		return -1;
	}

	*pnSemId = -1;
	
	key = ftok("/share/1.tmp",SemKey);
	
	if(key == -1)
	{
		printf("\n if(key == -1) errno=%d	[%s]\n",errno,strerror(errno));
		return -1;
	}
	else
	{
		printf("\n ftok key[%d]\n",key);
	}
		
	nSemid = semget(nSemid,SemNum ,0666|IPC_CREAT);

	if(-1 == nSemid)
	{
		printf("\n if(key == -1) errno=%d	[%s]\n",errno,strerror(errno));
		return -1;
	}

	*pnSemId = nSemid;

	return 0;
}

//nSemNumber为信号量集的序号(0 1 2 3 ...)
//这里实现一次只操作一个
//semflag 设置为IPC_NOWAIT
int Sem_P(int nSemId,int nSemNumber,short semflag)//请求资源 
{
	int ret = -1;
	struct sembuf stuSemBuf = {0};

	if(nSemId < 0 || 
		nSemNumber < 0)
	{
		printf("\n param error  [%s %d]\n",__FUNCTION__,__LINE__);
		return -1;
	}
	
	memset(&stuSemBuf,0,sizeof(struct sembuf));

	stuSemBuf.sem_num = nSemNumber;
	stuSemBuf.sem_op = SemOpNegative;
	stuSemBuf.sem_flg = semflag;

	ret = semop(nSemId,&stuSemBuf,1);// 1为操作的个数
	
	if(-1 == ret)
	{
		printf("\n nSemNumber[%d] failed  Sem_P    errno=%d	[%s]\n",nSemNumber,errno,strerror(errno));
		return -1;
	}

	printf("\n nSemNumber[%d] success Sem_P   ",nSemNumber);
	return 0;
}

int Sem_V(int nSemId,int nSemNumber,short semflag)
{
	int ret = -1;
	struct sembuf stuSemBuf = {0};

	if(nSemId < 0 || 
		nSemNumber < 0)
	{
		printf("\n param error  [%s %d]\n",__FUNCTION__,__LINE__);
		return -1;
	}
	
	memset(&stuSemBuf,0,sizeof(struct sembuf));

	stuSemBuf.sem_num = nSemNumber;
	stuSemBuf.sem_op = SemOpPositive;
	stuSemBuf.sem_flg = semflag;
	
	ret = semop(nSemId,&stuSemBuf,1);// 1为操作的个数
	if(-1 == ret)
	{
		printf("\n  nSemNumber[%d] failed  Sem_V   errno=%d	[%s]\n",nSemNumber,errno,strerror(errno));
		return -1;
	}

	printf("\n nSemNumber[%d]  success  to Sem_V   ",nSemNumber);
	
	return 0;
}

void *func_1(void* pArg)
{
	static int i =0;
	int ret = -1;
	while(1)
	{
		i++;

		ret = Sem_P(gs_nSemid,i%SemNum,IPC_NOWAIT);
		
		sleep(i%3);
	}
	
	return (void *)0;
}

void *func_2(void* pArg)
{
	static int i =0;
	int ret = -1;

	sleep(10);
	
	while(1)
	{
		i++;

		ret = Sem_V(gs_nSemid,i%SemNum,IPC_NOWAIT);
		sleep(i%5);
	}
	
	return (void *)0;
}


int main()
{
	pthread_t thread01_id = -1;
	pthread_t thread02_id = -1;

	int ret = -1;
	ret = Sem_init(&gs_nSemid,SemNum);
	if(-1 == ret)
	{
		printf("\n Sem_init error ! \n");
		return -1;
	}

	printf("\n Sem_init  gs_nSemid=%d  SemNum=%d\n",gs_nSemid,SemNum);

    pthread_create(&thread01_id, NULL, func_1, NULL);

	pthread_create(&thread02_id, NULL, func_2, NULL);

//semctl(gs_nSemid,0,IPC_RMID);删除信号量
	while(1)
	{
		sleep(1000);
	}
	return 0;
}




运行结果:


./a.out

 

 ftok key[-1929294457]

 

 Sem_init  gs_nSemid=0  SemNum=5

 

 nSemNumber[1] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[2] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[3] success Sem_P   

 nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[0] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[1] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[2] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[3] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[0] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[1]  success  to Sem_V   

 nSemNumber[1] success Sem_P   

 nSemNumber[2]  success  to Sem_V   

 nSemNumber[2] success Sem_P   

 nSemNumber[3] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[3]  success  to Sem_V   

 nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[0] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[1] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[4]  success  to Sem_V   

 nSemNumber[2] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[3] success Sem_P   

 nSemNumber[4] success Sem_P   

 nSemNumber[0] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[0]  success  to Sem_V   

 nSemNumber[1]  success  to Sem_V   

 nSemNumber[2]  success  to Sem_V   

 nSemNumber[1] success Sem_P   

 nSemNumber[2] success Sem_P   

 nSemNumber[3] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[3]  success  to Sem_V   

 nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[0] success Sem_P   

 nSemNumber[1] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 nSemNumber[4]  success  to Sem_V   

 nSemNumber[2] failed  Sem_P    errno=11 [Resource temporarily unavailable]

 

 

查看信号量id控制的某个具体的资源,比如说第五个资源。

展示出了P操作和V操作的结合情况。

P请求资源,减一操作,无资源时阻塞或者设置errno马上返回。

V释放资源,加1操作,使得其他线程可以请求资源

 

  C:\Users\zhouzhenhe\Desktop\3.txt (41 hits)

Line 12:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 22:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 33:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 39:  nSemNumber[4]  success  to Sem_V   

Line 43:  nSemNumber[4] success Sem_P   

Line 54:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 59:  nSemNumber[4]  success  to Sem_V   

Line 63:  nSemNumber[4] success Sem_P   

Line 72:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 76:  nSemNumber[4]  success  to Sem_V   

Line 83:  nSemNumber[4] success Sem_P   

Line 94:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 99:  nSemNumber[4]  success  to Sem_V   

Line 103:  nSemNumber[4] success Sem_P   

Line 114:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 119:  nSemNumber[4]  success  to Sem_V   

Line 123:  nSemNumber[4] success Sem_P   

Line 132:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]

Line 136:  nSemNumber[4]  success  to Sem_V   

Line 143:  nSemNumber[4] success Sem_P   

Line 154:  nSemNumber[4] failed  Sem_P    errno=11 [Resource temporarily unavailable]