linux 信号量sem

一、信号量

信号量如同一盏红绿信号灯,用于临界资源(如公路、人行道)的管理。信号量是一种特殊的变量,访问具有原子性。

P等待:信号量的值为0时,不能减,则进行阻塞休眠。相当于绿灯变红灯,不可以走。

V信号:信号量加1,则信号量的值变大,如果为1,则可以唤醒其他阻塞的线程。相当于有红灯变带有秒数的绿灯。

二、信号量相关函数

#include<semaphore.h>

//信号量变量声明
sem_t sem;

//初始化一个信号量,可以设置一个默认值value,[0,max unsigned int)
int sem_init(sem_t *sem,int pshared,unsigned int value);

//销毁信号量
int sem_destroy(sem_t * sem)

//原子操作方式信号量减1,信号量为0则阻塞不能减1。阻塞休眠
int sem_wait(sem_t *sem)

//原子操作方式信号量减1,信号量为0则不能减1。不阻塞直接返回
int sem_trywait(sem_t *sem)

//信号量加1,可以唤醒正在等待的该信号量的任何被阻塞的线程
int sem_post(sem_t *sem)

//获取信号量sem的当前值,把该值保存sval中
int sem_getvalue(sem_t *sem,int *sval);

三、二值信号量

相当于一盏红绿灯,只有红或绿两种状态(绿灯是没有带秒数的)。

1、作为锁使用

        作锁使用,信号量初始值为1,但不同线程的临界区不同。

2、追踪线程。

追踪线程,信号量初始值为0,如主线启动子线程后,进入sem_wait()进入阻塞,等待另一线程sem_post().然后主线才能继续执行。

四、使用案列

ndk-samples中工程native-codec中有一looper类,进行跨线程通信。

#include "looper.h"

#include <assert.h>
#include <jni.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <semaphore.h>

// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
#include <android/log.h>
#define TAG "NativeCodec-looper"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)


struct loopermessage;
typedef struct loopermessage loopermessage;

struct loopermessage {
    int what;
    void *obj;
    loopermessage *next;
    bool quit;
};



void* looper::trampoline(void* p) {//执行线程循环
    ((looper*)p)->loop();
    return NULL;
}

looper::looper() {
    sem_init(&headdataavailable, 0, 0);//头信息可用
    sem_init(&headwriteprotect, 0, 1);//头写入保护
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    pthread_create(&worker, &attr, trampoline, this);//创建线程
    running = true;
}


looper::~looper() {
    if (running) {
        LOGV("Looper deleted while still running. Some messages will not be processed");
        quit();//终止线程
    }
}

void looper::post(int what, void *data, bool flush) {//外部线程添加消息事件
    loopermessage *msg = new loopermessage();
    msg->what = what;
    msg->obj = data;
    msg->next = NULL;
    msg->quit = false;
    addmsg(msg, flush);
}

void looper::addmsg(loopermessage *msg, bool flush) {
    sem_wait(&headwriteprotect);//写入保护信号量>=1可减1继续执行。写入保护信号量为0,则先等待该信号量其他地方加1后,方可减1执行。
    loopermessage *h = head;

    if (flush) {//清空
        while(h) {
            loopermessage *next = h->next;
            delete h;
            h = next;
        }
        h = NULL;
    }
    if (h) {//追加到链表尾部
        while (h->next) {
            h = h->next;
        }
        h->next = msg;
    } else {
        head = msg;//作为头部
    }
    LOGV("post msg %d", msg->what);
    sem_post(&headwriteprotect);
    sem_post(&headdataavailable);//数据可用信号量标记是否用信息可用
}

void looper::loop() {
    while(true) {
        // wait for available message
        sem_wait(&headdataavailable);//数据可用信号量先判断否用有信息可用

        // get next available message
        sem_wait(&headwriteprotect);//写保护信号量如果非0,先减1,继续执行。如果0则进入等待。
        loopermessage *msg = head;
        if (msg == NULL) {
            LOGV("no msg");
            sem_post(&headwriteprotect);
            continue;
        }
        head = msg->next;
        sem_post(&headwriteprotect);//取一个消息后,写保护信号量加1。

        if (msg->quit) {
            LOGV("quitting");
            delete msg;
            return;
        }
        LOGV("processing msg %d", msg->what);
        handle(msg->what, msg->obj);//处理消息
        delete msg;
    }
}

void looper::quit() {
    LOGV("quit");
    loopermessage *msg = new loopermessage();
    msg->what = 0;
    msg->obj = NULL;
    msg->next = NULL;
    msg->quit = true;
    addmsg(msg, false);
    void *retval;
    pthread_join(worker, &retval);//等待自线程结束
    sem_destroy(&headdataavailable);//销毁信号量
    sem_destroy(&headwriteprotect);
    running = false;
}

void looper::handle(int what, void* obj) {
    LOGV("dropping msg %d %p", what, obj);
}

        

linux sem信号量_嘟嘟拌饭酱的博客-CSDN博客_linux sem

判断sem信号量为零_操作系统——信号量_weixin_39765588的博客-CSDN博客

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gdliweibing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值