3.14、信号量

1.信号量的介绍

  • 信号量则是一种计数器,可以用来同步多个线程之间的操作。当线程需要访问某个受保护的资源时,它需要先获取信号量。如果信号量的值大于零,表示当前没有线程访问该资源,线程可以获取该资源并将信号量的值减一;否则,线程需要等待,直到有其他线程释放了该资源并增加了信号量的值。

  • 在锁中使用信号量,通常是为了解决生产者消费者问题。在生产者消费者问题中,有一个缓冲区用于存放生产者生产的数据,消费者需要从缓冲区中取出数据进行消费。当缓冲区为空时,消费者需要等待生产者生产数据并通知消费者;当缓冲区满时,生产者需要等待消费者消费数据并通知生产者。

2.信号量的相关函数

  • 信号量的类型 sem_t
  • int sem_init(sem_t *sem, int pshared, unsigned int value);初始化一个信号量。
  • int sem_destroy(sem_t *sem);销毁并释放信号量资源
  • int sem_wait(sem_t *sem);等待信号量,如果信号量值为0,则阻塞等待,否则减少信号量值并返回。
  • int sem_trywait(sem_t *sem);尝试等待,不阻塞
  • int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
  • int sem_post(sem_t *sem);等待多久
  • int sem_getvalue(sem_t *sem, int *sval);获取信号量中的值

3.信号量函数的使用介绍

信号量的类型 sem_t
int sem_init(sem_t *sem, int pshared, unsigned int value);
    - 初始化信号量
    - 参数:
        - sem : 信号量变量的地址
        - pshared : 0 用在线程间 ,非0 用在进程间
        - value : 信号量中的值

int sem_destroy(sem_t *sem);
    - 释放资源

int sem_wait(sem_t *sem);
    - 对信号量加锁,调用一次对信号量的值-1,如果值为0,就阻塞

int sem_trywait(sem_t *sem);

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
    - 对信号量解锁,调用一次对信号量的值+1


4.用信号量实现生产者消费者模型

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

using namespace std;

// 创建互斥锁
pthread_mutex_t mutex;
// 创建信号量
sem_t psem, csem;

struct Node
{
    
    
    int num;
    Node * next;
    Node(): num(0), next(nullptr) {
    
    }
    Node(int _num): num(_num), next(nullptr) {
    
    }
};

Node * head = nullptr;

void * producer(void * arg)
{
    
    
    while (1)
    {
    
    
        // psem减少1
        sem_wait(&psem);
        // 加锁
        pthread_mutex_lock(&mutex);
        Node * newNode = new Node(rand() % 1000);
        newNode->next = head;
        head = newNode;

        printf ("add node, num: %d, tid: %ld\n", newNode->num, pthread_self());

        // 解锁
        pthread_mutex_unlock(&mutex);
        // csem加1
        sem_post(&csem);
        usleep(100);
    }
    pthread_exit(nullptr);
}

void * customer(void * arg)
{
    
    
    while (1)
    {
    
    
        sem_wait(&csem);
        pthread_mutex_lock(&mutex);

        Node * tmp = head;
        head = head->next;
        printf ("del node, num: %d, tid: %ld\n", tmp->num, pthread_self());
        delete tmp;
        tmp = nullptr;

        pthread_mutex_unlock(&mutex);
        sem_post(&psem);
        usleep(100);
    }
    pthread_exit(nullptr);
}

int main()
{
    
    
    // 初始化互斥锁和信号量
    pthread_mutex_init(&mutex, nullptr);
    sem_init(&psem, 0, 10);
    sem_init(&csem, 0, 0);

    // 创建5个生产者和5个消费者
    pthread_t ptid[5], ctid[5];

    for (int i = 0; i < 5; i ++ )
    {
    
    
        pthread_create(&ptid[i], nullptr, producer, nullptr);
        pthread_create(&ctid[i], nullptr, customer, nullptr);
    }


    // 主线程回收线程
    for (int i = 0; i < 5; i ++ )
    {
    
    
        pthread_join(ptid[i], nullptr);
        pthread_join(ctid[i], nullptr);
    }


    // 释放锁和信号量
    ptherad_mutex_destory(&mutex);
    sem_destroy(&psem);
    sem_destroy(&csem);

    pthread_exit(nullptr);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/z2812470857/article/details/130118779