linux信号量的理解及使用

xiaoxiao2021-02-28  84

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

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

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

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

    释放保护资源(V操作)

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

 

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

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

初始化:

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

 

 

 

1.信号量的创建

       #include <sys/types.h>

       #include <sys/ipc.h>

       #include <sys/sem.h>

 

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

 

(1)keyftok函数获取

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

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

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

 

 

 

2.信号量的资源操作(PV

#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_NOWAITSEM_UNDO

 

4.信号量的删除

       #include <sys/types.h>

       #include <sys/ipc.h>

       #include <sys/sem.h>

 

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

 

设置cmdIPC_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]

转载请注明原文地址: https://www.6miu.com/read-29288.html

最新回复(0)