免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2163 | 回复: 1
打印 上一主题 下一主题

信号灯使用解惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-22 16:36 |只看该作者 |倒序浏览

                                                信号灯是作为进程或线程之间同步或互斥的,信号灯分为有名信号灯和基于内存的"无名"信号灯.
有名信号灯对应与sem_open,sem_wait,sem_post,sem_close,sem_unlink等操作.
而"无名"信号灯则对应于sem_init,sem_wait,sem_post,sem_destory等操作.
有名信号灯之所以叫有名信号灯,是因为,在sem_open的时候要指定一个name,这个信号灯由name参数标识,name通常指代文件系统中的某个文件.
而"无名"信号灯是基于内存的信号灯,它们由应用程序分配信号灯的内存空间,然后由系统初始化它们的值.
[color="#000000"]1.sem_open需注意事项
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
oflag参数可以是O_CREAT(创建一个信号灯)或O_CREAT|O_EXCL(如果没有指定的信号灯就创建),
如果指定了O_CREAT,那么也得指定第三个和第四个参数,
如果不指定的话,mode和value值会取默认值.如果你认为value的默认值为1,那你就错了,value的默认值为内核现在能支持的最大值.
#include stdio.h>
#include stdlib.h>
#include pthread.h>
#include fcntl.h>
#include errno.h>
#include sys/stat.h>
#include semaphore.h>
//#define SEM_MODE  (S_IRUSR | S_IWUSR)
int main(int argc, char *argv[])
{
    int value;
    sem_t* psem;
    psem = sem_open("test1",O_CREAT);
    //psem = sem_open("test1",O_CREAT,SEM_MODE,1);
    if(psem==SEM_FAILED) {
        printf("sem error\n");
        printf("%s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }
    sem_getvalue(psem,&value);
    printf("%d\n",value);
    sem_close(psem);
    sem_unlink("test1");
    return 0;
}
# gcc test.c -lrt
# ./a.out
134513772
value参数指定信号灯的初始值,通常用来指定共享资源的数量.该初始不能超过SEM_VALUE_MAX,这个常值必须低于为32767.二值信号灯的初始值通常为1
如果指定了O_CREAT(而没有指定O_EXCL),那么只有所需的信号灯尚未存在时才初始化它,
所需信号灯已存在条件下指定O_CREAT不是一个错误,该标志的意思仅仅是“如果所需信号灯尚未存在,那就创建并初始化它”。
但是所需信号灯等已存在条件下指定O_CREAT|O_EXCL却是一个错误,下面的例子会证实这一点。
[color="#660099"]2.Posix有名信号灯的值是随内核持续的.也就是说,一个进程创建了一个信号灯,这个进程结束后,这个信号灯还存在,并且信号灯的值也不会改变。
我们修改一下上面的代码,去掉sem_unlink,并把sem_open中的oflag设为O_CREAT|O_EXCL,
前面说过,如果所需信号灯等已存在条件下,sem_open指定O_CREAT|O_EXCL是一个错误.现在证实一下:
#include stdio.h>
#include stdlib.h>
#include pthread.h>
#include fcntl.h>
#include errno.h>
#include sys/stat.h>
#include semaphore.h>
#define SEM_MODE  (S_IRUSR | S_IWUSR)
int main(int argc, char *argv[])
{
    int value;
    sem_t* psem;
    psem = sem_open("test1",O_CREAT|O_EXCL,SEM_MODE,1);
    if(psem==SEM_FAILED) {
        printf("sem error\n");
        printf("%s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }
    sem_getvalue(psem,&value);
    printf("%d\n",value);
    sem_close(psem);
//    sem_unlink("test1");
    return 0;
}
$ gcc test1.c  -lrt
$ ./a.out
1
$ ./a.out
sem error
File exists
运行第二次的时候,由于第一次sem_open以后没有sem_unlink,所以信号灯还是在内核存在的,
第二次运行时由于信号灯已存在,而且sem_open指定O_CREAT|O_EXCL,所以出错.
[color="#660099"]

[color="#660099"]3.当持有某个信号灯锁的进程没有释放它就终止时,内核并不给该信号灯解锁.
#include stdio.h>
#include stdlib.h>
#include unistd.h>
#include pthread.h>
#include fcntl.h>
#include errno.h>
#include sys/stat.h>
#include semaphore.h>
#define SEM_MODE  (S_IRUSR | S_IWUSR)
int main(int argc, char *argv[])
{
    int i;
    int ret_val;
    int value;
    
    sem_t* psem;
    psem = sem_open("test3",O_CREAT,SEM_MODE,1);
    if(psem==SEM_FAILED) {
        printf("sem error\n");
        printf("%s\n",strerror(errno));
    }
    printf("Begin to create process...\n");
    sem_getvalue(psem,&value);
    printf("%d\n",value);
    if (fork() == 0 ) {//son
        printf("son process\n");
        sem_wait(psem);
        printf("son in the critical region\n");
        sem_post(psem);
        sem_close(psem);
        exit(1);
    }
    printf("fathre process\n");
    sem_wait(psem);
    printf("father in the critical region\n");
    sem_post(psem);
    printf("Now, the main process returns.\n");
    sem_close(psem);
    sem_unlink("test3");
    return 0;
}
$ gcc test.c -lrt
$ ./a.out
Begin to create process...
1
son process
son in the critical region
fathre process
father in the critical region
Now, the main process returns.
可以看到上面的程序执行很好,
但是如果在子进程中把exit提前至sem_post之前
if (fork() == 0 ) {//son
    printf("son process\n");
    sem_wait(psem);
    printf("son in the critical region\n");
    [color="#ff0000"]exit(1);
    sem_post(psem);
    sem_close(psem);
}
$ gcc test.c -lrt
$ ./a.out
Begin to create process...
1
son process
son in the critical region
fathre process
在这里一直等待下去
可见当子进程sem_wait->exit后,父进程会一直在sem_wait处等待.
4.有名信号灯既可用于线程间的同步,又可以用于进程间的同步.
5.posix有名信号灯是通过内核持续的,一个进程创建一个信号灯,另外的进程可以通过该信号灯的外部名(创建信号灯使用的文件名)来访问它。
posix基于内存的信号灯的持续性却是不定的,
如果基于内存的信号灯是由单个进程内的各个线程共享的,那么该信号灯就是随进程持续的,当该进程终止时它也会消失。
如果某个基于内存的信号灯是在不同进程间同步的,该信号灯必须存放在共享内存区中,这时只要该共享内存区存在,该信号灯就存在。
6.基于内存的信号灯应用于进程很麻烦,而有名信号灯却很方便,
基于内存的信号灯比较适合应用于一个进程的多个线程。
reference:
Posix多线程编程学习笔记(三)—信号灯
Linux 系统编程 ->进程通讯 -> 信号灯
               
               
               
               
               
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/86590/showart_2128192.html

论坛徽章:
0
2 [报告]
发表于 2013-04-13 14:19 |只看该作者
不错的尝试   
我也做过第三个尝试
3.当持有某个信号灯锁的进程没有释放它就终止时,内核并不给该信号灯解锁.

但是有的人说只要进程退出,内核就会释放相关的信号灯
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP