参考链接如下:
在apue的介绍里,信号量(semaphore)是一个计数器,用于多进程、多线程对共享数据的访问。为了获取共享资源,进程需要执行下列步骤:
1.测试控制该资源的信号量。
2.若此信号量的值为正,则进程可以使用该资源。进程将信号量值减1,表示它使用了一个资源单位。
3.若此信号量的值为0,则进程进入休眠状态,直至信号量的值大于0 。进程被唤醒后,返回到 1 操作。
上述操作中的信号量增、减操作都是原子操作。可以使用下述流程图来表述信号量的使用。
在使用信号量集合时,需要先进行创建,之后需要对创建好的信号量集合进行控制设置。控制函数使用semctl:
-
int semctl(int semid, int semnum, int cmd, ... /*arg*/);
-
semid : 创建信号量集合时的id号。
-
semnum : 需要控制的信号量集合的下标号。 (0----N)
-
cmd : 参考下表。也可以参考apue。
-
args : 这个参数是一个联合体形式。
-
union semun {
int val; /* used for SETVAL only */
struct semid_ds *buf; /* used for IPC_STAT and IPC_SET */
ushort *array; /* used for GETALL and SETALL */
};
cmd
|
Effect
|
SETVAL
|
Set the value of the specified semaphore to the value in the val member of the passed-in union semun.
|
GETVAL
|
Return the value of the given semaphore.
|
SETALL
|
Set the values of all the semaphores in the set to the values in the array pointed to by the array member of the passed-in union semun. The semnum parameter to semctl() isn't used.
|
GETALL
|
Gets the values of all the semaphores in the set and stores them in the array pointed to by the array member of the passed-in union semun. The semnum parameter to semctl() isn't used.
|
IPC_RMID
|
Remove the specified semaphore set from the system. The semnum parameter is ignored.
|
IPC_STAT
|
Load status information about the semaphore set into the struct semid_ds structure pointed to by the buf member of the union semun.
|
semctl()函数可以用来根据semnum参数来对指定的信号量进行初始化,通常用在 对 val 值 进行SETVAL操作,赋值为0. 此时使用semop()函数进行信号量获取时,由于信号量值为0,所以会发生等待,直到此val的值被修改成正整数。
-
int semop(int semid, struct sembuf *sops, unsigned int nsops);
进行上面流程图操作时使用 semop 函数。semop()函数执行信号量集合上的操作数组,并且是原子操作。semop函数的参数
-
/* Members might not be in this */
-
-
struct sembuf {
-
ushort sem_num; //集合中信号量对象的下标
-
short sem_op; //操作数,正整数、负整数、0
-
short sem_flg; //操作标识 IPC_NOWAIT、SEM_UNDO等。
-
};
sem_op 由调用者赋值,通常在P操作时做-1操作,如果此时val的值为0,则会发生等待。做V操作时+1操作,val的值+1,表示释放了一个信号量资源。
sem_op
|
What happens
|
Negative
|
Allocate resources. Block the calling process until the value of the semaphore is greater than or equal to the absolute value of sem_op. (That is, wait until enough resources have been freed by other processes for this one to allocate.) Then add (effectively subtract, since it's negative) the value of sem_op to the semaphore's value.
|
Positive
|
Release resources. The value of sem_op is added to the semaphore's value.
|
Zero
|
This process will wait until the semaphore in question reaches 0.
|
下面是实例代码.
由于调用了线程创建,编译时需要链接pthread库: gcc sem_fok.c -lpthread -o sem_fok
-
/* sem_fork.c */
-
#include<sys/types.h>
-
#include<sys/ipc.h>
-
#include<sys/sem.h>
-
#include<unistd.h>
-
#include<stdio.h>
-
#include<stdlib.h>
-
#include<pthread.h>
-
-
#define DELAY_TIME 3 /*为了突出演示效果,等待几秒*/
-
#define THREAD_NUMS (4)
-
-
/*定义联合体*/
-
union semun
-
{
-
int val;
-
struct semid_ds *buf;
-
unsigned short *array;
-
};
-
-
/*函数声明*/
-
int init_sem(int sem_id,int init_value);/*信号量初始化(赋值)函数*/
-
int del_sem(int sem_id); /*从系统中删除信号量的函数*/
-
int sem_p(int sem_id); /*P 操作函数*/
-
int sem_v(int sem_id); /*V 操作函数*/
-
-
-
int sem_p_idx(int sem_id, int idx);/*P 操作函数*/
-
-
/*信号量初始化(赋值)函数*/
-
int init_sem_idx(int sem_id,int idx, int init_value);
-
/*V 操作函数*/
-
int sem_v_idx(int sem_id, int idx);
-
static void thrRunWait(int idx);
-
static int g_sem_id = 0;
-
-
-
int main(void)
-
{
-
pthread_t pidRun[THREAD_NUMS];
-
int i = 0;
-
//int sem_id = 0;
-
-
g_sem_id = semget(ftok(".", 'a'), THREAD_NUMS, 0666|IPC_CREAT);
-
if(g_sem_id == -1){ //创建失败后,先清空,重新创建
-
printf("semget exist!\n");
-
g_sem_id = semget(ftok(".", 'a'), 0, 0666);
-
if(g_sem_id == -1){
-
printf("semget attach failed!\n");
-
return -1;
-
}
-
semctl(g_sem_id, 0, IPC_RMID);
-
-
g_sem_id = semget(ftok(".", 'a'), THREAD_NUMS, 0666|IPC_CREAT);
-
if(g_sem_id != -1){
-
printf("semget create ok!\n");
-
// return -1;
-
}
-
}
-
// init_sem(sem_id, THREAD_NUMS);
-
for(i = 0; i < THREAD_NUMS; i++){
-
init_sem_idx(g_sem_id, i, 0);
-
}
-
-
for(i = 0; i < THREAD_NUMS; i++){
-
pthread_create(&pidRun[i], NULL, (void *)thrRunWait, (void *)i);
-
}
-
sleep(5);
-
printf("main start V action--\n");
-
sem_v_idx(g_sem_id, 3);
-
sem_v_idx(g_sem_id, 2);
-
sem_v_idx(g_sem_id, 1);
-
sem_v_idx(g_sem_id, 0);
-
printf("main V action over\n");
-
-
sleep(3);
-
return 0;
-
}/* main() end*/
-
-
-
-
/*信号量初始化(赋值)函数*/
-
int init_sem_idx(int sem_id,int idx, int init_value)
-
{
-
union semun sem_union;
-
sem_union.val=init_value; /*init_value为初始值*/
-
if(semctl(sem_id,idx,SETVAL,sem_union)==-1)
-
{
-
perror("Initialize semaphore");
-
return -1;
-
}
-
return 0;
-
}
-
/*信号量P操作创建线程*/
-
static void thrRunWait(int idx)
-
{
-
printf("thrRunWait idx:%d waiting---!\n", idx);
-
sem_p_idx(g_sem_id, idx);
-
printf("thrRunWait idx:%d run over!\n", idx);
-
return ;
-
}
-
-
/*信号量初始化(赋值)函数*/
-
int init_sem(int sem_id,int init_value)
-
{
-
union semun sem_union;
-
sem_union.val=init_value; /*init_value为初始值*/
-
if(semctl(sem_id,0,SETVAL,0)==-1)
-
{
-
perror("Initialize semaphore");
-
return -1;
-
}
-
return 0;
-
}
-
-
/*从系统中删除信号量的函数*/
-
int del_sem(int sem_id)
-
{
-
union semun sem_union;
-
if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
-
{
-
perror("Delete semaphore");
-
return -1;
-
}
-
}
-
-
/*P 操作函数*/
-
int sem_p_idx(int sem_id, int idx)
-
{
-
struct sembuf sem_b;
-
sem_b.sem_num=idx; /*信号量编号,这里单个信号量的编号应该为0*/
-
sem_b.sem_op=-1; /*信号量操作,取值为-1表示P操作*/
-
sem_b.sem_flg=SEM_UNDO; /*在进程没释放信号量而退出时,系统自动释放该进程中未释放的信号量*/
-
if(semop(sem_id,&sem_b,1)==-1) /*进行P操作*/
-
{
-
perror("P operation");
-
return -1;
-
}
-
return 0;
-
}
-
-
/*V 操作函数*/
-
int sem_v_idx(int sem_id, int idx)
-
{
-
struct sembuf sem_b;
-
sem_b.sem_num=idx; /*信号量编号,这里单个信号量的编号应该为0*/
-
sem_b.sem_op=1; /*信号量操作,取值为+1表示V操作*/
-
sem_b.sem_flg=SEM_UNDO; /*在进程没释放信号量而退出时,系统自动释放该进程中
-
未释放的信号量*/
-
if(semop(sem_id,&sem_b,1)==-1) /*进行V 操作*/
-
{
-
perror("V operation");
-
return -1;
-
}
-
return 0;
-
}
阅读(2498) | 评论(0) | 转发(0) |