信号量:进程同步控制
共享资源(临界资源):同一时刻只允许一个进程使用的资源
临界区 ---》 使用临界资源的代码区域
原子操作 ----》 不能被中断的操作
P、V操作:
P操作 -1 使用资源之前进行P操作
V操作 +1 使用资源之后释放资源
信号量定义:对资源访问控制的计数器。当其>0时,计数器的值代表能被访问的临界资源的个数。当其<0时,代表等待使用临界资源的进程个数。
信号量操作:
创建获取:
int semget((key_t) key, int nsems, int flg);
如果semget调用的是创建信号量集,那么nsems就代表信号量集中信号量的个数。否则,nsems无作用。
参数解释:
key:所创建或打开信号量集的键值。需要是唯一的非零整数。
nsems:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。几乎总是取值为1.
flag:调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过 | 表示
返回值说明:
如果成功,则返回信号量集的IPC标识符(一个正数)。
如果失败,则返回-1,errno被设定成以下的某个值
EACCES:没有访问该信号量集的权限
EEXIST:信号量集已经存在,无法创建
EINVAL:参数nsems的值小于0或者大于该信号量集的限制;或者是该key关联的信号量集已存在,并且nsems
大于该信号量集的信号量数
ENOENT:信号量集不存在,同时没有使用IPC_CREAT
ENOMEM :没有足够的内存创建新的信号量集
ENOSPC:超出系统限制
初始化:
对于新创建的信号量集进行初始化
int semctl(int semid, int num, int cmd/*SETVAL*/, union semun un);
sem_id是由semget返回的信号量标识符。
sem_num与前面一个函数相同。
cnd:表示将要采取的动作。最常用的两个值如下:
SETVAL:用来把信号量初始化为一个已知的值。这个值通过union semun中的val成员设置。其作用是在信号量第一次使用之前对它进行设置。
IPC_RMID:用于删除一个无需继续使用的信号量标志符。
semun联合结构的定义:
1. semun是在linux/sem.h中定义的:
2. union semun
3. {
4. int val;/*value for SETVAL*/
5. struct semid_ds *buf;/*buffer for IPC_STAT&IPC_SET*/
6. ushort *array;/*array for GETALL&SETALL*/
7. struct seminfo *__buf;/*buffer for IPC_INFO*/
8. void *__pad;
9. };
注:初始化时是对信号量集中某一信号量的下标进行初始化。
V操作:使用临界资源之后+1
int semop(int semid, struct sembuf buf[], size_t nops);
参数解释:
参数semid是一个通过semget函数返回的一个信号量标识符
参数nops标明了参数semoparray所指向数组中的元素个数
参数buf是一个struct sembuf结构类型的数组指针,
结构sembuf来说明所要执行的操作,其定义如下:
1. struct sembuf
2. {
3. unsigned short sem_num;
4. short sem_op;
5. short sem_flg;
6. } ;
释放:int semctl(int semid, int num, int cmd/*IPC_RMID*/);
#define __SEM_H
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <sys/sem.h>
{
int val;
};
void sem_p();
void sem_v();
void sem_del();
#endif
{
semid = semget((key_t)1234, 1, 0664);
if(semid == -1)
{
semid = semget((key_t)1234, SIZE, IPC_CREAT | 0664);
if(semid == -1)
{
perror("");
exit(0);
}
union semun un;
un.val = 1;
semctl(semid, 0, SETVAL, un);
}
}
void sem_p() // 完成P操作
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
}
void sem_v() // 完成V操作
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
{
perror("");
}
}
void sem_del() // 释放信号量集
{
semctl(semid, 0, IPC_RMID);
}
{
sem_get();
sem_p();
int i = 0;
for(;i < 20; ++i)
{
sleep(1);
printf("sema running\n");
}
}
{
sem_get();
sem_p();
int i = 0;
for(;i < 10; ++i)
{
sleep(1);
printf("semb running\n");
}
}