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

原文地址:https://www.cnblogs.com/zhangxuechao/p/11709936.html