Fork me on GitHub

LinuxC进程通信-信号量


信号量的创建或者打开

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

参数说明:
返回值:若成功,返回一个信号集的标识符,失败返回-1
key:第一个参数由ftok()函数得到的键值
nsems:第二个参数指明要创建的信号集包含的信号个数,如果只是打开信号集,把nsems设置为0即可
semflg:第三个参数为操作标志
IPC_CREATE:调用semget()时,他会将此值与系统中其他信号集的key进行比较奥,如果存在相同的key,
说明信号集已存在,此时返回该信号集的标识符,否则新建一个信号集并返回其标识符。
IPC_EXCL:该宏须和IPC_CREATE一起使用,否则没有意义。当semflg取IPC_CREATE|IPC_EXCL时,
表示如果发现该信号集已经存在,则返回错误,错误吗为EEXIST

创建信号量并对信号集中所有信号进行初始化的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int createsem(const char *pathname,int proj_id,int members,int init_val)
{
key_t msgkey;
int index,sid;
union semun semopts;

// 获取键值
if((msgkey = ftok(pathname,proj_id)) == -1)
{
perror("semget call failed.\n");
return -1;
}

if((sid = semget(msgkey,members,IPC_CREATE|0666)) == -1)
{
perror("semget call failed.\n");
return -1;
}

// 初始化操作
semopts.val = init_val;
for(index = 0;index < members;index++)
{
semctl(sid,index,SETVAL,semopts);
}
return (sid);
}

信号量的操作

信号量的值与相应资源的使用情况有关,当它的值大于0时,表示当前可用资源的数量,当它的值小于0时,其绝对值表示等待使用该资源的进程个数。信号量的值仅能由PV操作来改变。

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

参数说明:
返回值:若成功,返回0,失败,返回-1
semid:semid为信号集的标识符
sops:指向进行操作的结构体数组首地址
nsops: 指出将要进行操作的信号的个数

semop的第二个参数sops指向的结构体数组中,每个sembuf结构体对应一个特定信号的操作
因此对信号进行操作必须熟悉该数据结构

1
2
3
4
5
struct sembuf{
ushort sem_num; /* 信号在信号集中的索引 */
short sem_op; /* 操作类型 见下表*/
short sem_flg; /* 操作标志 */
}
取值范围 操作意义
sem_op > 0 信号加上sem_op的值,表示进程释放控制的资源
sem_op = 0 如果没有设置IPC_NOWAIT,则调用进程进入睡眠状态,直到信号值为0;否则进程不会睡眠,直接返回EAGAIN
sem_op < 0 信号加上sem_op的值。如果没有设置IPC_NOWAIT,则调用进程阻塞,z直到资源可用。否则进程直接返回EAGAIN

对一个信号集中的某个信号进行操作的P,V函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* P操作函数 */
int sem_p(int semid,int index)
{
struct sembuf buf = {0,-1,IPC_NOWAIT};
if(index < 0)
{
perror("index of array cannot equals a minux value!");
return -1;
}

buf.sem_num = index;
if(semop(semid,&buf,1) == -1)
{
perror("a wrong operation to semaphore occurred!");
return -1;
}

return 0;
}

信号集的控制

使用信号量时,往往需要对信号集进行一些控制操作,比如删除信号集,对内核维护的信号集的数据结构semid_ds进行设置,获取信号集中信号值等。

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

参数说明:
semid:信号集的标识符
semnum:标识一个特定的信号
cmd:指明控制操作的类型
最后的”…”说明函数的参数是可选的,他依赖于第三个参数cmd,他通过共用体变量semun选择要操作的参数

semun定义在include/sem.h

1
2
3
4
5
6
7
union semun{
int val;
struct semid_ds *buf;
ushort *array;
struct seminfo *buf;
void *pad;
};

各字段的含义如下:

  • val:仅用于SETVAL操作类型,设置某个信号的值等于val
  • buf: 用于IPC_STAT和IPC_SET操作,存取semid_ds结构
  • array:用于SETALL和GETALL操作
  • buf:为控制IPC_INFO提供的缓存

实例

server创建一个信号集,并对信号量循环减1,相当于分配资源。client执行时检查信号量,如果其值大于0代表有资源可用,继续执行,如果小于0代表资源已经分配完毕,进程client退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*************************************************************************
> File Name: server.c
> Author: xiaorui
> Mail: wustxiao@gmail.com
> Created Time: 2017年11月26日 星期日 15时22分23秒
> Function: server创建一个信号集,并对信号量循环减1,相当于分配资源。
client执行时检查信号量,如果其值大于0代表有资源可用,继续执行,
如果小于0代表资源已经分配完毕,进程client退出。
************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<linux/sem.h>
#include<stdlib.h>
#include<unistd.h>

#define MAX_RESOURCE 5

int main(void)
{
key_t key;
int semid;
struct sembuf sbuf = {0,-1,IPC_NOWAIT};
union semun semopts;

if((key = ftok(".",'s')) == -1)
{
perror("ftok error!\n");
exit(1);
}

if((semid = semget(key,1,IPC_CREAT|0666)) == -1)
{
perror("semget error!\n");
exit(1);
}

semopts.val = MAX_RESOURCE;
if(semctl(semid,0,SETVAL,semopts) == -1)
{
perror("semctl error!\n");
exit(1);
}

while(1)
{
if(semop(semid,&sbuf,1) == -1)
{
perror("semop error!\n");
exit(1);
}
sleep(3);
}
exit(0);

}


/*************************************************************************
> File Name: client.c
> Author: xiaorui
> Mail: wustxiao@gmail.com
> Created Time: 2017年11月26日 星期日 15时45分53秒
************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h>

int main(void)
{
key_t key;
int semid,semval;
union semun semopts;

if((key = ftok(".",'s')) == -1)
{
perror("ftok error!\n");
exit(1);
}

if((semid = semget(key,1,IPC_CREAT|0666)) == -1)
{
perror("semget error!\n");
exit(1);
}

while(1)
{
if((semval = semctl(semid,0,GETVAL,0)) == -1)
{
perror("semctl error!\n");
exit(1);
}
if(semval > 0)
{
printf("Still %d resources can be used\n",semval);
}
else
{
printf("No more resources can be used!\n");
break;
}
sleep(3);
}
}


坚持原创技术分享,您的支持将鼓励我继续创作
-------------本文结束感谢您的阅读-------------
0%