Linux下多线程编程-信号量

时间:2021-09-07 15:14:10

今天来谈谈线程的同步--信号量。

首先来看看一些概念性的东西:

如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。例如Window API函数SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者。

在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

线程同步的方式和机制

临界区、互斥量、事件、信号量四种方式

临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别

1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。

2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享

3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目

4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作

这里我们重点讨论下信号量。

  • int sem_init(sem_t *sem, int pshared, unsigned int value);,其中sem是要初始化的信号量,为0时表示只能在当前进程的多个线程之间共享,pshared表示此信号量是在进程间共享还是线程间共享,value是信号量的初始值。
  • int sem_destroy(sem_t *sem);,其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy销毁。
  • int sem_wait(sem_t *sem);等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0,则线程阻塞。相当于P操作。成功返回0,失败返回-1。
  • int sem_post(sem_t *sem); 释放信号量,让信号量的值加1。相当于V操作。

上代码:

/*

线程信号量测试用例

*/

#include <pthread.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <semaphore.h>

 

sem_t sem;

int running = 1;

 

void * producter_f(void *arg)

{

    int semval = 0;

    while(running)

    {

        usleep(1);

        sem_post(&sem);

        sem_getvalue(&sem,&semval);

        printf("生产,总数量:%d\n",semval);

    }

}

 

void * consumer_f(void *arg)

{

    int semval = 0;

    while(running)

    {

        usleep(1);

        sem_wait(&sem);

        sem_getvalue(&sem,&semval);

        printf("消费,总数量:%d\n",semval);

    }

}

int main()

{

    pthread_t consumer_t;

    pthread_t producter_t;

    int err;

    sem_init(&sem,0,16);

 

    err = pthread_create(&producter_t,NULL,(void *)producter_f,NULL);

 

        printf("%d",err);

 

    pthread_create(&consumer_t,NULL,(void *)consumer_f,NULL);

 

    sleep(1);

    running = 0;

 

    pthread_join(producter_t,NULL);

    pthread_join(consumer_t,NULL);

    sem_destroy(&sem);

 

    return 0;

}