semaphore很类似windows下的kernel object,一旦创建,可以被多个进程使用,当然一个进程中多个线程也可以使用semaphore来互斥。谈到互斥,一般semaphore的值就是1。man 7 sem_overview可以看到很多有用的信息。
Semaphore和pipe一样,也有有名的和无名的两种。无名的嘛,在父子进程间使用比较方便,有名的嘛,在"不搭界"的多进程中使用很方便。
这里贴一段代码,代码最能说明问题,其他都参考manual就OK了。
old_mask = umask(0);
super_mmsem = sem_open("/supermm", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, 1);
if (super_mmsem == SEM_FAILED) {
fprintf(stderr, "Create mm semaphore failed. Name: %s, Reason: %s\n", "/supermm", strerror(errno));
return 1;
}
umask(old_mask);
............
/* Release after used */
if (super_mmsem != NULL) {
sem_close(super_mmsem);
sem_unlink("/supermm");
}
2. sem_open的第一个参数需要注意,是这个有名sem的path,这里path不能写成/tmp/aaa.sem这样的格式,因为Linux下,sem都是创建在/dev/shm目录下的(Linux的/dev/shm是一个tmpfs类型的特殊fs,就像/proc, /sys一样,用mount命令就可以看到),而且会加上sem.这样的prefix,所以,这里代码里的值是/supermm,这样创建出来的文件就是/dev/shm/sem.supermm了,千万不要写路径。名字可以以/打头,不以/打头也是可以的。
3. 和windows的kernel object一样,sem也有counter,只有所有open了该sem的进程都sem_close了,该sem才会真正被内核销毁。使用sem_unlink就可以删掉该sem对应的文件。
创建好了,就可以使用了,和windows kernel object一样,使用也是调用sem_open首先得到一个sem的handle(当然这里flag就不能写O_CREAT了),然后sem_wait就是将该sem的值减1,由于sem定义规定了sem的值不能小于0,所以如果sem_wait之后的sem的值小于1的话,sem_wait就会block,直到有人增加了sem的值才会return,这样达到互斥的效果。sem_post就是给sem的值加1。
{
super_mmsem = sem_open("/supermm", O_RDWR);
if (super_mmsem == SEM_FAILED) {
/* How can we do now? */
fprintf(stderr, "Open semaphore %s failed. Reason: %s\n", "/supermm", strerror(errno));
return 1;
}
}
......
if (sem_wait(super_mmsem) == -1) {
fprintf(stderr, "Call sem_wait failed. Reason: %s\n", strerror(errno));
return 1;
}
......
if (sem_post(super_mmsem) == -1) {
fprintf(stderr, "Call sem_post failed, this is FATAL, maybe cause deadlock. Reason: %s\n", strerror(errno));
return 1;
}
使用非常方便,记得用完之后sem_close。
That's it。不过注意使用无名semaphore的话,API和这些是不一样的,诸如有sem_init这样的API存在。所以如果使用无名sem的话,请参考linux manual。