和有名信号量类似,无名信号也是进程之间/线程之间通信的主要手段,唯一不同的是他不能用在不同进程之间。当然如果把无名信号量放在多个进程都可以访问的共享内存里,也可以实现进程之间的通信,但这主要还是借助于共享内存的机制。下面将根据使用无名信号量依赖的头文件、需要链接的库文件、常用的函数分别进行介绍。
依赖头文件:#include
<semaphore.h>
链接依赖库:
需要链接到libpthread.so,因此makefile里需要指定-lpthread
重要函数列表:
int
sem_init(sem_t *sem, int pshared, unsigned int value);
无名信号量的初始化函数,这个函数体现了无名信号量和有名信号量的主要区别,不同于有名信号量的初始化函数sem_open(),它不需要指定一个文件名,只需要传递一个进程、线程都可以访问的信号量指针进去就可以。如果需要在同一个进程的不同线程之间访问,那么pshared必须设置为0,并且第一参数必须保证每个线程都可以访问;如果需要在不同进程间访问,那么pshared必须设置为1,并且第一个参数必须放在共享内存区域。这个函数的地三个参数value指定了该信号量初始化的值,它代表系统刚开始可用的系统资源的个数。
当上面的函数返回为0时,表示函数调用成功;当返回为-1的时候,代表出错,错误代码放在errno里面,可以通过strerror(errno)打印出来。
int
sem_post(sem_t *sem);
unlock无名信号量,并且把可用的资源个数加1,唤醒等待当前信号量的线程或进程,让被唤醒的进程或线程可以拿到锁。函数返回值同上。
int
sem_wait(sem_t *sem);
int
sem_trywait(sem_t *sem);
int
sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
上面的三个函数都能查询当前有没有可用资源,如果有:就抢到锁并把当前可用的资源数目减1。如果没有可用资源:不同的是sem_wait()会把当前进程或线程加入到休眠队列,直到被唤醒;而sem_trywait()函数在系统没有可用资源的情况下会立即返回错误,并把错误代码设置为EAGAIN,当前进程或线程不会被阻塞;而sem_timewait()在没有可用资源的情况下,最长会被阻塞abs_timeout的时长,然后返回错误,并把错误代码设置为ETIMEDOUT。
int
sem_getvalue(sem_t *sem, int *sval);
得到当前信号量的值(代表当前系统可用资源的数量),并把它放到sval指向的内存里面。
代码示例
#include
<stdio.h>
#include
<stdint.h>
#include
<stdlib.h>
#include
<string.h>
#include
<assert.h>
#include
<sys/types.h>
#include
<sys/ipc.h>
#include
<sys/sem.h>
#include
<fcntl.h> /* For O_* constants */
#include
<sys/stat.h> /* For mode constants */
#include
<semaphore.h>
#include
<errno.h>
sem_t
clnt_sem;
int
create_done = 0;
void
state_thread1()
{
while(1) {
if
(!create_done) continue;
printf("%s:
Wait semp....\n", __FUNCTION__);
sem_wait(&clnt_sem);
printf("%s:
Wait semp done: semp comes\n", __FUNCTION__);
}
}
void
state_thread2()
{
while(1) {
printf("%s:
Wait semp....\n", __FUNCTION__);
sem_wait(&clnt_sem);
printf("%s:
Wait semp done: semp comes\n", __FUNCTION__);
sleep(10);
}
}
void
main(void)
{
pthread_t
ftids;
int
ret;
ret
= sem_init(&clnt_sem,0, 3);
if
(ret < 0) {
printf("%s\n",
strerror(errno));
}
pthread_create(&ftids,
NULL, (void *)state_thread1, NULL);
pthread_create(&ftids,
NULL, (void *)state_thread2, NULL);
create_done =
1;
sem_post(&clnt_sem);
while(1) {
printf("IN
Clnt main process\n");
sleep(10);
}
编译和运行结果:
[[email protected]
testcases]$ gcc -o sem_nameless sem_nameless.c -lpthread
[[email protected]
testcases]$ ./sem_nameless
IN
Clnt main process
state_thread2:
Wait semp....
state_thread2:
Wait semp done: semp comes
state_thread1:
Wait semp....
state_thread1:
Wait semp done: semp comes
state_thread1:
Wait semp....
state_thread1:
Wait semp done: semp comes
state_thread1:
Wait semp....
state_thread1:
Wait semp done: semp comes
state_thread1:
Wait semp....
IN
Clnt main process
state_thread2:
Wait semp....