信号量

1.1 概述

信号量广泛用于【线程】和【进程】之间的互斥行为。****信号本质上一个【非负数整数计数器】,用于管理控制线程或者进程之间的共享资源访问问题。

  • 当信号量大于 0 时,当前线程或者进程可以访问对应的共享资源。
  • 当前信号量为 0 时,当前线程或者进程,处于阻塞状态。
  • 核心内容是 PV 操作,P 操作信号量 - 1 ,V 操作信号量 + 1

1.2 信号量对应函数
1.2.1 信号量数据类型

sem_t 在 <semaphore.h> 头文件中

typedef union
{
char __size[__SIZEOF_SEM_T];
long int __align;
} sem_t;
​
1.2.2 sem_init 初始化

函数文档

#include <semaphore.h> 
int sem_init(sem_t *sem, int pshared, unsigned int value)
  • 函数功能:
    • 用于初始化一个信号量变量,提供必要的参数,限制当前信号量是针对于【线程操作】还是【进程操作】
  • 函数参数
    • sem_t *sem : 信号量变量地址
    • int pshared : 控制值当前信号量,限制内容为线程还是进程,线程参数要求为 0, 不等于 0 为进程间操作。建议 0 线程, 1 进程。
    • unsigned int value : 信号量初始化数据,通常情况下为 1
  • 返回值
    • 成功返回 0
    • 失败返回 -1
1.2.3 sem_wait P 操作/等待操作

函数文档

#include <semaphore.h> 
int sem_wait(sem_t *sem)
  • 函数功能:
    • 信号量 P 操作,当前信号量 -= 1。
    • 如果为 0 当前线程/进程进入阻塞状态。
    • 如果不为 0,信号量 -= 1,同时可以执行目标线程/进程代码。
  • 函数参数:
    • sem_t *sem : 信号量变量地址
  • 返回值类型
    • 成功返回 0
    • 失败返回 -1
1.2.4 sem_post V 操作/释放操作

函数文档

#include <semaphore.h> 
int sem_post(sem_t *sem)
  • 函数功能:
    • 信号量 V 操作,当前信号量 += 1
    • 信号量不为 0,相当于解除与当前信号量相关的其他线程/进程****阻塞状态
  • 函数参数:
    • sem_t *sem : 信号量变量地址
  • 返回值类型
    • 成功返回 0
    • 失败返回 -1
1.2.5 sem_destroy 销毁操作

函数文档

#include <semaphore.h> 
int sem_destroy (sem_t *sem)
  • 函数功能:
    • 销毁当前信号量变量
  • 函数参数:
    • sem_t *sem : 信号量变量地址
  • 返回值类型
    • 成功返回 0
    • 失败返回 -1

信号量互斥

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
​
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
​
// 信号量【互斥】
​
sem_t sem;
​
void printf_value(char *str);
void *thread_funcationA(void *arg);
void *thread_funcationB(void *arg);
​
int main(int argc, char const *argv[])
{   
    // 信号量初始化
    sem_init(&sem, 0, 1);
​
    pthread_t td1 = 0;
    pthread_t td2 = 0;
​
    pthread_create(&td1, NULL, thread_funcationA, "Hello World!");
    pthread_create(&td2, NULL, thread_funcationB, "C/C++ best in the world!");
​
    pthread_join(td1, NULL);
    pthread_join(td2, NULL);
​
    // 信号量销毁
    sem_destroy(&sem);
    return 0;
}
​
void *thread_funcationA(void *arg)
{
    // 信号量 P 操作
    sem_wait(&sem);
    printf_value((char *)arg);
​
    // 信号量 V 操作
    sem_post(&sem);
}
void *thread_funcationB(void *arg)
{
    // 信号量 P 操作
    sem_wait(&sem);
    printf_value((char *)arg);
​
    // 信号量 V 操作
    sem_post(&sem);
}
​
void printf_value(char *str)
{
    while (*str != '\0')
    {
        printf("%c", *str);
        fflush(stdout);
        sleep(1);
        str += 1;
    }
​
    printf("\n");
}

信号量同步

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
​
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
​
// 信号量【同步】
// 可以利用信号量同步,控制线程的执行次序,从而保证项目启动,执行任务一致性。
​
sem_t sem1, sem2, sem3;
​
void printf_value(char *str);
void *thread_funcationA(void *arg);
void *thread_funcationB(void *arg);
void *thread_funcationC(void *arg);
​
int main(int argc, char const *argv[])
{   
    sem_init(&sem1, 0, 1);
    sem_init(&sem2, 0, 0);
    sem_init(&sem3, 0, 0);
​
    pthread_t td1 = 0;
    pthread_t td2 = 0;
    pthread_t td3 = 0;
​
    pthread_create(&td1, NULL, thread_funcationA, "Hello");
    pthread_create(&td2, NULL, thread_funcationB, "World");
    pthread_create(&td3, NULL, thread_funcationC, "!!!");
​
    pthread_join(td1, NULL);
    pthread_join(td2, NULL);
    pthread_join(td3, NULL);
   
    sem_destroy(&sem1);
    sem_destroy(&sem2);
    sem_destroy(&sem3);
​
    return 0;
}
​
void *thread_funcationA(void *arg)
{
    // 信号量 P 操作
    sem_wait(&sem1);
    printf_value((char *)arg);
​
    // 信号量 V 操作
    sem_post(&sem2);
}
​
void *thread_funcationB(void *arg)
{
    // 信号量 P 操作
    sem_wait(&sem2);
    printf_value((char *)arg);
​
    // 信号量 V 操作
    sem_post(&sem3);
}
​
void *thread_funcationC(void *arg)
{
    // 信号量 P 操作
    sem_wait(&sem3);
    printf_value((char *)arg);
​
    // 信号量 V 操作
    sem_post(&sem1);
}
​
void printf_value(char *str)
{
    while (*str != '\0')
    {
        printf("%c", *str);
        fflush(stdout);
        sleep(1);
        
        str += 1;
    }
​
    printf("\n");
}