zoukankan      html  css  js  c++  java
  • 信号量(Posix)

    Posix信号量分为有名信号量和无名信号量

    Posix

    1. Posix有名信号量
    有名信号量既可以用于线程间的同步也可以用于进程间的同步
    sem都是创建在/dev/shm目录下,名字格式sem.xxx,只需要指定一个name名字即可。这是为什么名字被限制在NAME_MAX-4

    sem_t *sem_open(const char *name, int oflag);
    sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

    创建并初始化有名信号灯
    参数
    name:信号灯的外部名字
    oflag:选择创建或打开一个现有的信号灯
    mode:权限位
    value:信号灯初始值
    返回值
    成功时返回指向信号灯的指针,出错时为SEM_FAILED

    oflag参数可以是0、O_CREAT(创建一个信号灯)或O_CREAT|O_EXCL(如果没有指定的信号灯就创建),如果指定了O_CREAT,那么第三个和第四个参数是需要的;该初始不能超过SEM_VALUE_MAX,这个常值必须低于为32767。二值信号灯的初始值通常为1,计数信号灯的初始值则往往大于1

    如果指定了O_CREAT(而没有指定O_EXCL),那么只有所需的信号灯尚未存在时才初始化它。所需信号灯已存在条件下指定O_CREAT不是一个错误。该标志的意思仅仅是“如果所需信号灯尚未存在,那就创建并初始化它”。但是所需信号灯等已存在条件下指定O_CREAT|O_EXCL却是一个错误

    int sem_unlink(const char *name);

    要等到所有打开该信号量的进程关闭该信号量后才删除该信号

    2. 举例

    sem_t *sem;
    
    //创建信号量,返回sem_t类型指针
    if((sem = sem_open(argv[1],O_RDWR | O_CREAT,0644,atoi(optarg))) == SEM_FAILED)
    {
        perror("sem_open() error");
        exit(-1);
    }
    //关闭打开的信号量
    sem_close(sem);
    
    sem_unlink(argv[1]);

    3. Posix无名信号量
    基于内存的信号量

    int sem_init(sem_t *sem, int pshared, unsigned int value);

    pshared:信号量是由进程内线程共享,还是由进程之间共享
    value:信号量的初始值

    如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在这个进程的所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量);如果 pshared 是非零值,那么信号量将在进程之间共享

    int sem_destroy(sem_t *sem);

    销毁一个有其它线程或进程当前阻塞的信号量将导致未定义行为
    使用一个已经销毁的信号量将导致未定义结果

    int sem_post(sem_t *sem);

    sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”,即同时对同一个信号量做加“1”操作的两个线程是不会冲突的

    int sem_wait(sem_t *sem);
    int sem_trywait(sem_t *sem);
    int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

    sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法
    sem_trywait()是函数sem_wait的非阻塞版,它直接将信号量sem减1,同时返回错误代码

    int sem_getvalue(sem_t *sem, int *sval);

    sem 指向的信号量当前值放置在 sval 指向的整数上
    注:信号量的值可能在 sem_getvalue() 返回时已经被更改

    4. 举例
    建两个线程,这两个线程各自将自己的一个整型变量i从1 递增到100,并通过信号量控制递增的过程,即这两个整型变量的差不能超过5

    void* th_fn1(void* arg)  
    {      
        int i;      
        for(i = 0; i < 100; ++i)      
        {          
            sem_wait(&sem1);          
            printf("number in thread1 is %d
    ",i);          
            sem_post(&sem2);      
        }  
        pthread_exit((void*)"thread1exit
    ");  
    }  
    void* th_fn2(void* arg)  
    {      
        int i;    
        for(i = 0; i < 100; ++i)  
        {          
            sem_wait(&sem2);  
            printf("number in thread2 is %d
    ",i);         
            sem_post(&sem1);  
        }     
        pthread_exit((void*)"thread2exit
    "); 
    }  
    int main(void)  
    {     
        void *tret;    
        sem_init(&sem1,0,5);  
        sem_init(&sem2,0,5);  
        pthread_t tid1,tid2;    
        pthread_create(&tid1,NULL,th_fn1,NULL);
        pthread_create(&tid2,NULL,th_fn2,NULL);   
        pthread_join(tid1,&tret);    
        pthread_join(tid2,&tret);    
        sem_destroy(&sem1);   
        sem_destroy(&sem2);    
        return 0;  
    }  

    5. 互斥量和信号量的区别
    互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的
    同步:是指在互斥的基础上,通过其它机制实现访问者对资源的有序访问

  • 相关阅读:
    四套读取方案
    java的分层开发
    位移运算符
    反射
    多线程下的单例
    学生管理系统
    iOS-分段控制器-基本概念
    iOS-UITableView-处理cell上按钮事件(弹出警示框,页面跳转等)
    iOS-UIScrollView-图片缩放
    Xcode-Xcode 7.3 解决不能自动联想问题
  • 原文地址:https://www.cnblogs.com/zhangxuechao/p/11709936.html
Copyright © 2011-2022 走看看