POSIX- 有名信号量
使用范围: 线程同步,相关进程同步,无关进程同步
此文转自:http://blog.csdn.net/jiebaoabcabc/article/details/37904805
一、函数介绍
1.初始化打开有名信号量
#include<semaphore.h>
sem_t * sem_open (const char *name, intoflag, ...)
sem_t *sem_open(const char *name,int oflag,mode_tmode,unsigned int value);
函数功能:创建并初始化有名信号量
返回值:成功时返回指向信号量的指针,出错时为SEM_FAILED(NULL)
输入参数:1.name
mq_open、sem_open、shm_open这三个函数的name参数都使用“Posix IPC名字”,它可能某个文件系统中的一个真正的路径名,也可能不是;用做信号量外部名。
注意:这里的name不能写成/tmp/aaa.sem这样的格式,因为在linux下,sem都是创建在/dev/shm目录下。你可以将name写成“/mysem”或“mysem”,创建出来的文件都是“/dev/shm/sem.mysem”,千万不要写路径。也千万不要写“/tmp/mysem”之类的。
2.oflag
配置有名信号量创建方式标志,可用取值为0(不创建信号量)、O_CREAT(创建一个信号量)或O_CREAT|O_EXCL(如果没有指定的信号量就创建),
当oflag =O_CREAT时,若name指定的信号量不存在时,则会创建一个,而且后面的mode和value参数必须有效。若name指定的信号量已存在,则直接打开该信号量,同时忽略mode和value参数。
当oflag = O_CREAT|O_EXCL时,若name指定的信号量已存在,该函数会直接返回error。
3.mode
当oflag参数指定了O_CREAT标志且 name指定的信号量名不存在时,这个参数才有作用。作用用来指定操作权限位,例:0644
4.value
当oflag参数指定了O_CREAT标志且 name指定的信号量名不存在时,这个参数才有作用。
作用用于指定信号量的初始化值。
2.关闭有名信号量
#include<semaphore.h>
int sem_close (sem_t *sem);
Link with -pthread.
函数功能:通过传入的sem关闭有名信号量,允许任何分配到此信号量资源的进程关闭信号量。关闭一个信号量并没有将它从系统中删除。Posix有名信号量是随内核持续的。即使当前没有进程打开着某个信号量,它的值仍然保持。
返回值:On success sem_close() returns 0; on error, -1 is returned,with errno set to indicate the error.
错误:EINVAL
sem is not a valid semaphore.
输入参数:sem
指向描述信号量的结构体的指针。
3.注销有名信号量
#include <semaphore.h>
int sem_unlink(const char *name);
Link with -pthread.
函数功能:通过有名信号量名从系统中销毁信号量,如果有任何的处理器或是线程引用这个信号量,sem_unlink()函数不会起到任何的作用。必须是最后一个使用该信号量的进程来执行sem_unlink才有效。也就是要等待最后一个sem_close发生。
理论上是这样的,但是实际测试结果并不是这样,sem_unlink甚至能在临界区中执行成功,所以调用需要谨慎。
返回值:On success sem_unlink() returns 0; onerror, -1 is returned, with errno set to indicate the error.
错误:EACCES
The caller does not have permission tounlink this semaphore.
ENAMETOOLONG
name was too long.
ENOENT
There is no semaphore with the given name.
输入参数:name
创建有名信号量时使用的信号量名。
//--------------------------------↓下面的是有名无名信号量共用函数↓----------------------------------
4.申请信号量 P操作
#include<semaphore.h>
int sem_wait(sem_t *sem);
函数功能:sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。
返回值:成功返回0,错误的话信号量的值不改动,返回-1.errno设定来标识错误.
错误:EINTR The call was interrupted by a signalhandler; seesignal(7).
//调用被信号处理中断
EINVAL sem is not a valid semaphore.
//sem不是有效的信号量
The following additional error can occurfor sem_trywait():
//下面的错误是sem_trywait()可能发生的:
EAGAIN The operation could not beperformed without blocking(i.e., the
semaphore currently has the value zero).
//除了锁定无法进行别的操作(如信号量当前是0值).
The following additional errors canoccur for sem_timedwait():
//下面的错误是sem_timedwait()可能发生的:
EINVAL The value of abs_timeout.tv_nsecsis less than 0, orgreater than or
equal to 1000 million.
//abs_timeout.tv_nsecs 的值比0小或者大于等于1000毫秒(译者注:纳秒的值不能比0小,不能比1秒大)
ETIMEDOUT
The call timed out before the semaphore could be locked.
//在信号量锁定之前就超时了
输入参数:sem
表明哪一个信号量需要申请信号量。
5.申请信号量 无阻塞版本
#include<semaphore.h>
int sem_trywait(sem_t *sem);
函数功能:无阻塞获取信号量,如果信号量为0也不会阻塞。
返回值:执行成功返回0,执行失败返回 -1且信号量的值保持不变。
错误:EINTR:The callwas interrupted by a signalhandler.(信号处理函数中断调用)
EINVAL: sem is not a valid semaphore.(信号量sem值无效)
EAGAIN: The operation could not beperformed without blocking(i.e., the semaphore currently has the value zero).
输入参数:sem
表明哪一个信号量需要申请信号量。
6.申请信号量 带超时版本
#include<semaphore.h>
int sem_timedwait (sem_t *sem, const structtimespec *abstime);
函数功能:带超时的阻塞获取信号量,如果
返回值:成功时返回 0;错误时,信号量的值没有更改,-1被返回,并设置 errno 来指明错
错误:ETIMEDOUT阻塞超时
EINTR
这个调用被信号处理器中断,参看 signal(7)。
EINVAL
sem 不是一个有效的信号量。
对 sem_trywait()有如下额外的错误:
EAGAIN
操作不能执行而不阻塞(也就是说,信号量当前值是零)。
对 sem_timedwait()有如下额外的错误:
EINVAL
abs_timeout.tv_nsecs 的值小于0,或者大于等于 100 百万。
输入参数:1.sem 指向描述当前信号量的结构体指针
2. abstime 绝对时间,设定超时时间值
7.释放信号量 V操作
#include<semaphore.h>
int sem_post(sem_t *sem);
函数功能:信号量加1的原子操作
返回值:sem_post()成功时返回 0;错误时,信号量的值没有更改,-1被返回,并设置 errno 来指明错误。
错误: EINVAL
sem 不是一个有效的信号量。
EOVERFLOW
信号量允许的最大值将要被超过。
输入参数:sem
表明哪一个信号量需要释放信号量。
8.查询信号量
#include<semaphore.h>
int sem_getvalue(sem_t *sem,int *sval);
函数功能:原子查询当前信号量的值
返回值:sem_getvalue()成功时返回 0;错误时,返回 -1,同时把 errno设置为合适的值。
错误:EINVAL
sem 不是一个有效的信号量。
输入参数:sem 指向描述当前信号量的结构体指针
输出参数:sval 返回当前信号量的值
二、例子 无关进程有名信号量实现临界区测试
文件一:创建有名信号量,并向共享内存发送数据 编译需加-pthread
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h> // O_CREAT
#include <sys/types.h>
#include <semaphore.h> // sem -lpthread
#include <sys/shm.h> // shm
#define SHMKEY 123123123
#define SHMMSZ 64
char SEM_NAME[] = "linjie";
int main()
{
int shmid;
char *shm = NULL;
sem_t *mutex = (sem_t*)NULL;
// 防止信号量文件没清除干净
if(sem_unlink(SEM_NAME))
{
perror("name semaphore unlink err");
}
//create & initialize semaphore
mutex = sem_open(SEM_NAME, O_CREAT, 0644, 1);
if(mutex == SEM_FAILED) // if == NULL
{
perror("can`t create name semaphore");
if(sem_unlink(SEM_NAME))
{
perror("name semaphore unlink err");
}
exit(-1);
}
// if file exist O_CREAT | O_EXCL return err
if(sem_open(SEM_NAME, O_CREAT | O_EXCL, 0644, 1) == SEM_FAILED)
{
perror("can`t create name semaphore");
}
// create the shared memory segment whit this key
shmid = shmget(SHMKEY, SHMMSZ, IPC_CREAT | 0666);
if(shmid < 0)
{
perror("shmget err");
exit(-1);
}
// attach this segment to virtual memory mmap
shm = (char *)shmat(shmid, 0, 0);
if(shm == NULL)
{
perror("shmid err");
exit(-1);
}
sem_wait(mutex);
strcpy(shm, "linjie");
strcat(shm, "linjie");
strcat(shm, "linjie");
sem_post(mutex);
while(*shm != '*')
{
sleep(1);
}
sem_close(mutex);
//
if(sem_unlink(SEM_NAME))
{
perror("name semaphore unlink err");
}
shmctl(shmid, IPC_RMID, 0);
exit(0);
}
文件二:打开创建好的有名信号量,从共享内存中获取数据 编译需加-pthread
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h> // O_CREAT
#include <sys/types.h>
#include <semaphore.h> // sem -lpthread
#include <sys/shm.h> // shm
#define SHMKEY 123123123
#define SHMMSZ 64
char SEM_NAME[] = "linjie";
int main()
{
int shmid;
char *shm = NULL;
sem_t *mutex = (sem_t*)NULL;
printf("hl\n");
//create & initialize semaphore
mutex = sem_open(SEM_NAME, 0);
if(mutex == SEM_FAILED) // if == NULL
{
perror("can`t create name semaphore");
if(sem_unlink(SEM_NAME))
{
perror("name semaphore unlink err");
}
exit(-1);
}
// get the shared memory segment whit this key
shmid = shmget(SHMKEY, SHMMSZ, 0666);
if(shmid < 0)
{
perror("shmget err");
exit(-1);
}
// attach this segment to virtual memory mmap
shm = (char *)shmat(shmid, 0, 0);
if(shm == NULL)
{
perror("shmid err");
exit(-1);
}
sem_wait(mutex);
printf("read: %s\n", shm);
strcpy(shm, "*");
if(sem_unlink(SEM_NAME))
{
perror("name semaphore unlink err");
}
sem_post(mutex);
sem_close(mutex);
if(sem_unlink(SEM_NAME))
{
perror("name semaphore unlink err");
}
shmctl(shmid, IPC_RMID, 0);
exit(0);
}