linux进程线程同步之 - POSIX有名信号量

POSIX- 有名信号量

使用范围: 线程同步,相关进程同步,无关进程同步

此文转自:http://blog.csdn.net/jiebaoabcabc/article/details/37904805

一、函数介绍

1.初始化打开有名信号量

#include<semaphore.h>

sem_t * sem_open (const char *name, intoflag, ...)

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

函数功能创建并初始化有名信号量

返回值成功时返回指向信号量的指针,出错时为SEM_FAILED(NULL)

输入参数1.name

                   mq_open、sem_open、shm_open这三个函数的name参数都使用“Posix IPC名字”,它可能某个文件系统中的一个真正的路径名,也可能不是;用做信号量外部名

注意:这里的name不能写成/tmp/aaa.sem这样的格式,因为linux下,sem都是创建在/dev/shm目录下。你可以将name写成“/mysem”或“mysem”,创建出来的文件都是“/dev/shm/sem.mysem”,千万不要写路径。也千万不要写“/tmp/mysem”之类的。

                   2.oflag

                   配置有名信号量创建方式标志,可用取值为0(不创建信号量)O_CREAT(创建一个信号量)或O_CREAT|O_EXCL(如果没有指定的信号量就创建)

                   当oflag =O_CREAT时,若name指定的信号量不存在时,则会创建一个,而且后面的mode和value参数必须有效。若name指定的信号量已存在,则直接打开该信号量,同时忽略mode和value参数。

当oflag = O_CREAT|O_EXCL时,若name指定的信号量已存在,该函数会直接返回error。

                   3.mode

                   当oflag参数指定了O_CREAT标志 name指定的信号量名不存在时,这个参数才有作用。作用用来指定操作权限位,例:0644

                   4.value

                   当oflag参数指定了O_CREAT标志 name指定的信号量名不存在时,这个参数才有作用。

作用用于指定信号量的初始化值

 

2.关闭有名信号量

#include<semaphore.h>

int sem_close (sem_t *sem);

Link with -pthread.

函数功能:通过传入的sem关闭有名信号量,允许任何分配到此信号量资源的进程关闭信号量。关闭一个信号量并没有将它从系统中删除。Posix有名信号量是随内核持续的。即使当前没有进程打开着某个信号量,它的值仍然保持。

返回值:On success sem_close() returns 0; on error, -1 is returned,with errno set to indicate the error.

错误EINVAL

sem is not a valid semaphore.

输入参数:sem 

                   指向描述信号量的结构体的指针。

 

3.注销有名信号量

#include <semaphore.h>

int sem_unlink(const char *name);

Link with -pthread.

函数功能:通过有名信号量名从系统中销毁信号量,如果有任何的处理器或是线程引用这个信号量,sem_unlink()函数不会起到任何的作用。必须是最后一个使用该信号量的进程来执行sem_unlink才有效。也就是要等待最后一个sem_close发生。

      理论上是这样的,但是实际测试结果并不是这样,sem_unlink甚至能在临界区中执行成功,所以调用需要谨慎。

返回值:On success sem_unlink() returns 0; onerror, -1 is returned, with errno set to indicate the error.

错误EACCES

The caller does not have permission tounlink this semaphore.

           ENAMETOOLONG

name was too long.

           ENOENT

There is no semaphore with the given name.

输入参数:name

                   创建有名信号量时使用的信号量名。

//--------------------------------↓下面的是有名无名信号量共用函数↓----------------------------------

4.申请信号量  P操作

#include<semaphore.h>

int sem_wait(sem_t *sem);

函数功能:sem_wait函数也是一个原子操作,它的作用是从信号的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。

返回值:成功返回0,错误的话信号量的值不改动,返回-1.errno设定来标识错误.

错误:EINTR The call was interrupted by a signalhandler; seesignal(7).
//
调用被信号处理中断

EINVAL sem is not a valid semaphore.
//sem
不是有效的信号量

The following additional error can occurfor sem_trywait():
//
下面的错误是sem_trywait()可能发生的:

EAGAIN The operation could not beperformed without blocking(i.e., the
semaphore currently has the value zero).
//
除了锁定无法进行别的操作(如信号量当前是0).

The following additional errors canoccur for sem_timedwait():
//
下面的错误是sem_timedwait()可能发生的:

EINVAL The value of abs_timeout.tv_nsecsis less than 0, orgreater than or
equal to 1000 million.
//abs_timeout.tv_nsecs 
的值比0小或者大于等于1000毫秒(译者注:纳秒的值不能比0,不能比1秒大)

ETIMEDOUT
The call timed out before the semaphore could be locked.
//
在信号量锁定之前就超时了

输入参数:sem

         表明哪一个信号量需要申请信号量。

 

5.申请信号量  无阻塞版本

#include<semaphore.h>

int sem_trywait(sem_t *sem);

函数功能:无阻塞获取信号量,如果信号量为0也不会阻塞。

返回值执行成功返回0,执行失败返回 -1且信号量的值保持不变。

错误EINTRThe callwas interrupted by a signalhandler.(信号处理函数中断调用)

EINVAL: sem is not a valid semaphore.(信号量sem值无效)

EAGAIN: The operation could not beperformed without blocking(i.e., the semaphore currently has the value zero).

输入参数:sem

         表明哪一个信号量需要申请信号量。

 

6.申请信号量  带超时版本

#include<semaphore.h>

int sem_timedwait (sem_t *sem, const structtimespec *abstime);

函数功能:带超时的阻塞获取信号量,如果

返回值成功时返回 0;错误时,信号的值没有更改,-1被返回,并设置 errno 来指明错

错误:ETIMEDOUT阻塞超时

EINTR

这个调用被信号处理器中断,参看 signal(7)。

EINVAL

sem 不是一个有效的信号量。

对 sem_trywait()有如下额外的错误:

EAGAIN

操作不能执行而不阻塞(也就是说,信号量当前值是零)。

对 sem_timedwait()有如下额外的错误:

EINVAL

abs_timeout.tv_nsecs 的值小于0,或者大于等于 100 百万。

输入参数:1.sem 指向描述当前信号量的结构体指针

                   2. abstime 绝对时间,设定超时时间值

 

7.释放信号量   V操作

#include<semaphore.h>

int sem_post(sem_t *sem);
函数功能:信号量加1的原子操作

返回值sem_post()成功时返回 0;错误时,信号的值没有更改,-1被返回,并设置 errno 来指明错误。

错误: EINVAL

sem 不是一个有效的信号量

EOVERFLOW

信号量允许的最大值将要被超过。

 

输入参数:sem

         表明哪一个信号量需要释放信号量。

 

8.查询信号量

#include<semaphore.h>

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

函数功能:原子查询当前信号量的值

返回值sem_getvalue()成功时返回 0;错误时,返回 -1,同时把 errno设置为合适的值。

错误EINVAL

sem 不是一个有效的信号量

输入参数sem  指向描述当前信号量的结构体指针

输出参数sval  返回当前信号量的值

 

 

二、例子   无关进程有名信号量实现临界区测试

文件一:创建有名信号量,并向共享内存发送数据   编译需加-pthread

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>     // O_CREAT

#include <sys/types.h>
#include <semaphore.h> // sem  -lpthread
#include <sys/shm.h>   // shm

#define SHMKEY 123123123
#define SHMMSZ 64

char SEM_NAME[] = "linjie";

int main()
{
    int shmid;
    char *shm = NULL;
    sem_t *mutex = (sem_t*)NULL;

    // 防止信号量文件没清除干净
    if(sem_unlink(SEM_NAME))   
    {
        perror("name semaphore unlink err");
    }
    //create & initialize semaphore
    mutex = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if(mutex == SEM_FAILED)    // if == NULL
    {
        perror("can`t create name semaphore");
        if(sem_unlink(SEM_NAME))
        {
            perror("name semaphore unlink err");
        }
        exit(-1);
    }
    // if file exist  O_CREAT | O_EXCL return err
    if(sem_open(SEM_NAME, O_CREAT | O_EXCL, 0644, 1) == SEM_FAILED)
    {
        perror("can`t create name semaphore");
    }

    // create the shared memory segment whit this key
    shmid = shmget(SHMKEY, SHMMSZ, IPC_CREAT | 0666);
    if(shmid < 0)
    {
        perror("shmget err");
        exit(-1);
    }
    
    // attach this segment to virtual memory   mmap
    shm = (char *)shmat(shmid, 0, 0);
    if(shm == NULL)
    {
        perror("shmid err");
        exit(-1);
    }

    sem_wait(mutex);
    strcpy(shm, "linjie");
    strcat(shm, "linjie");
    strcat(shm, "linjie");
    sem_post(mutex);

    while(*shm != '*')
    {
        sleep(1);
    }
    
    sem_close(mutex);
    // 
    if(sem_unlink(SEM_NAME))
    {
        perror("name semaphore unlink err");        
    }
    shmctl(shmid, IPC_RMID, 0);
    
    exit(0);
}

文件二:打开创建好的有名信号量,从共享内存中获取数据  编译需加-pthread

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>     // O_CREAT

#include <sys/types.h>
#include <semaphore.h> // sem  -lpthread
#include <sys/shm.h>   // shm

#define SHMKEY 123123123
#define SHMMSZ 64

char SEM_NAME[] = "linjie";

int main()
{
    int shmid;
    char *shm = NULL;
    sem_t *mutex = (sem_t*)NULL;
    printf("hl\n");
    //create & initialize semaphore
    mutex = sem_open(SEM_NAME, 0);
    if(mutex == SEM_FAILED)    // if == NULL
    {
        perror("can`t create name semaphore");
        if(sem_unlink(SEM_NAME))
        {
            perror("name semaphore unlink err");
        }
        exit(-1);
    }
    
    // get the shared memory segment whit this key
    shmid = shmget(SHMKEY, SHMMSZ, 0666);
    if(shmid < 0)
    {
        perror("shmget err");
        exit(-1);
    }
    
    // attach this segment to virtual memory   mmap
    shm = (char *)shmat(shmid, 0, 0);
    if(shm == NULL)
    {
        perror("shmid err");
        exit(-1);
    }

    sem_wait(mutex);
    printf("read: %s\n", shm);
    strcpy(shm, "*");
    if(sem_unlink(SEM_NAME))
    {
        perror("name semaphore unlink err");        
    }    
    sem_post(mutex);   

    sem_close(mutex);
    if(sem_unlink(SEM_NAME))
    {
        perror("name semaphore unlink err");        
    }
    shmctl(shmid, IPC_RMID, 0);
    
    exit(0);
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值