POSIX线程库(三)线程同步——信号量

一、信号量是什么?

为什么需要用信号量?在POSIX线程库(二)线程同步轮询技术——一种笨笨方法 简单的变量+延迟的方法是一种非常不聪明的方法,主要原因是普通变量不能保证原子性,同时对标志的操作可能导致预料外的效果。荷兰科学家Dijkstra提出信号量的概念,它是一种特殊的变量,可以被递增递减,当两个或以上线程对这个信号量进行改变,由系统按顺序完成线程的请求。信号量常用来保护一段代码,保证一次只能被一个线程执行。

二、信号量API

使用一个信号量,其基本步骤是:

  • 声明一个信号量
  • 初始化一个信号量
  • 线程1使用sem_post增加信号量
  • 线程2中调用sem_wait条件阻塞完成信号同步
  • 销毁信号量

头文件#include <semaphore.h>

声明

sem_t bin_sem;

初始化

int sem_init(sem_t *sem,int pshared,unsigned int value);
  • sem_t * sem声明的信号量地址
  • int pshared 一般将其设置为0,表示这是一个局部信号量(单进程共享),迄今为止,Linux尚未支持多个进程共享(传递会失败)。
  • unsigned int value信号量初值
  • 返回值,0表示相安无事,反之创建失败

增加、减少信号量

int sem_post(sem_t * sem);
int sem_wait(sem_t * sem);

sem_waitsem_post都接受一个信号量地址,和初始化一样,成功0,失败!0。值得注意的是,sem_wait可能阻塞当前进程,阻塞的条件是,递减后为负数,也就是信号量为0,要想继续执行,需要调用sem_post完成信号量递增。

销毁

int sem_destory(sem_t * sem);

好吧!和所有信号量相关的API都需要传入信号量地址。当一些线程正在等待状态,返回非0,成功销毁则返回0。

三、Demo time!!!

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

sem_t t;

using namespace std;

void *thfun1(void *)
{
    sem_post(&t);
    
    for(int i=0;i<10;i++)
    {
        sem_wait(&t);
        cout<<"a";
    }
}

void* thfun2(void *)
{
    for(int i=0;i<10;i++)
    {

        cout<<"b";
        sem_post(&t);
        usleep(1);
    }
}
using namespace std;


int main()
{
    pthread_t th1,th2;
    sem_init(&t,0,0);
    pthread_create(&th1,NULL,thfun1,NULL);
    pthread_create(&th2,NULL,thfun2,NULL);

    pthread_join(th1,NULL);
    pthread_join(th2,NULL);
    sem_close(&t);

    
    return 0;
}

打印结果如下:

abababababababababab

20200802 才发现原来在Ubuntu下运行的结果并没有交错运行的效果。而且实际使用的时候你没有办法预估一个线程执行时间,因此需要找其他办法。

©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页