欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux学习——进程间通信之posix信号量的使用

程序员文章站 2022-06-04 21:59:49
...

1.概述

信号量(semaphore)是一种提供不同进程间或者一个给定进程不同线程之间的同步。 分为POSIX信号量和SystemV信号量,这里先学习POSIX信号量。

POSIX信号量又分为有名信号量和基于内存的信号量(无名信号量)。区别在于是否需要使用POSIX IPC名字来标识。

NOTE:Linux操作系统中,POSIX有名信号量创建在虚拟文件系统中 
一般挂载在/dev/shm,其名字以sem.somename的形式存在。

2.信号量操作

早在学操作系统那会,就直到信号量的PV操作,总结一下大概是这么回事:

P操作,也叫做等待(wait)一个信号量,该操作会测试信号量的值,如果其值小于或等于0,将把当前进程/线程投入睡眠,当该信号量变得大于0后就将它减1。
伪代码如下,这两步必须是原子操作。

while(sem <=0);
sem--;

V操作,挂出(post)一个信号量,该操作将信号量值加1
伪代码如下:

sem++;

信号量初始化的值的大小一般用于表示可用资源的数(例如缓冲区大小,之后代码中体现);如果初始化为1,则称之二值信号量,二值信号量的功能就有点像互斥锁了。

不同的是:互斥锁的加锁和解锁必须在同一线程执行,而信号量的挂出却不必由执行等待操作的线程执行。

3.POSIX信号量相关接口:

1.sem_init()初始化无名信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);

//pshared指定该信号量用于进程还是线程同步
//0-表示用于线程同步(所有线程可见)
//非0-表示用于进程同步(需要放在共享内存中)

2.sem_open()初始化有名信号量

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
Link with -pthread.
//套路跟之前的消息队列类似
//oflag可以设置为O_CREAT | O_EXCL (如果存在则返回错误)。
//mode可以设置为0644 自己可读写,其他用户和组内用户可读
//value表示信号量初始化的值

3.sem_wait()和sem_post()等待和挂出函数

#include <semaphore.h>
int sem_wait(sem_t *sem);//P操作
int sem_post(sem_t *sem);//V操作
Link with -pthread.

4.sem_timedwait()超时等待

 int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
 //跟sem_wait()类似,不过,如果P操作不能立即执行,该函数将投入睡眠
 //并等待abs_timeout中指定的时间。
 //如果超时依旧无法执行P操作,则返回timeout错误

4.1 无名信号量的创建

sem_t sem;
...  ...
sem_init(&sem, 0, 0) == -1);

4.2 有名信号量的使用


//有名信号量要指定一个名字somename,打开成功后
//将以sem.somename的形式存在于/dev/shm/目录下。 
//书中用二值信号量做互斥同步,这里我直接用mutex。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#define MAXSIZE 10
void *produce(void *); 
void *consume(void *);

typedef void *(*handler_t)(void *);//线程函数指针

struct _shared 
{
    int buff[MAXSIZE];

    sem_t *nempty;
    sem_t *nstored;
};//共享缓冲
typedef struct _shared shared;
shared shared_;
pthread_mutex_t mutex;//互斥锁
int nitems;//生产和消费的数目

int main(int argc,char **argv)
{
    if (argc !=2)
    {
        printf("usage:namedsem <#items>\r\n");
        exit(-1);
    }
    nitems=atoi(argv[1]);
    const char *const SEM_NEMPTY = "nempty";//信号量的“名字”
    const char *const SEM_NSTORED = "nstored";//信号量的“名字”
    pthread_t tid_produce;//生产者线程 id
    pthread_t tid_consume;//消费者线程 id
    //初始化信号量和互斥锁
    pthread_mutex_init(&mutex, NULL); 
    shared_.nstored=sem_open(SEM_NSTORED,O_CREAT|O_EXCL,0644,0);
    shared_.nempty=sem_open(SEM_NEMPTY,O_CREAT|O_EXCL,0644,MAXSIZE);
    memset(shared_.buff,0x00,MAXSIZE);

    //线程创建
    handler_t handler=produce;
    pthread_setconcurrency(2);
    if((pthread_create(&tid_produce,NULL,handler,NULL))<0)
    {
        printf("pthread_create error\r\n");
        exit(-1);
    }
//    sleep(5);
    handler=consume;
    if((pthread_create(&tid_consume,NULL,handler,NULL))<0)
    {
        printf("pthread_create error\r\n");
        exit(-1);
    }

    //线程回收
    pthread_join(tid_produce,NULL);
    pthread_join(tid_consume,NULL);

    //信号量锁销毁
    sem_unlink(SEM_NEMPTY);
    sem_unlink(SEM_NSTORED);
    pthread_mutex_destroy(&mutex);
    exit(0);
}



void *produce(void *args)
{
    int i;
    for(i=0;i<nitems;i++)
    {
        sem_wait(shared_.nempty);
        pthread_mutex_lock(&mutex);
        shared_.buff[i%MAXSIZE]=i;
        printf("add an item\r\n");
        pthread_mutex_unlock(&mutex);
        sem_post(shared_.nstored);
    }
    return NULL;
}


void *consume(void *args)
{
    int i;
    for(i=0;i<nitems;i++)
    {
        sem_wait(shared_.nstored);
        pthread_mutex_lock(&mutex);
        printf("consume an item\r\n");
        if(shared_.buff[i%MAXSIZE]!=i)
            printf("buff[%d]=%d\r\n",i,shared_.buff[i%MAXSIZE]);
        pthread_mutex_unlock(&mutex);
        sem_post(shared_.nempty);
    }
    return NULL;
}

项目2结尾

项目1分析回顾

红黑树和红黑树实现map和set

模式和锁和posix信号量的使用

第一个项目

相关标签: posix信号量