linux——信号量

1.头文件-semaphore.h

2.信号量类型

  • sem_t sem;
  • 加强版的互斥锁

3.主要函数

  • 初始化信号量

em_init(sem_t *sem,int pshared,unsigned int value);

0-线程同步

1-进程同步

value-最多有几个线程操作共享数据

  • 销毁信号量

sem_destroy(sem_t *sem);

  • 加锁

sem_wait(sem_t *sem);

调用一次相当于对sem做了一次 -- 操作

如果sem值为0,线程会阻塞

  • 尝试加锁

sem_trywait(sem_t *sem);

sem == 0;加锁失败,不阻塞,直接发

  • 限时尝试加锁

sem_timewait(sem_t *sem,xxxx);

  • 解锁++

sem_post(sem_t *sem);

对sem做了++ 操作

4.练习

使用信号量实现生产者,消费者模型。

复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

sem_t producer_sem;
sem_t customer_sem;

typedef struct node
{
	int data;
	struct node* next;
}Node;

Node* head = NULL;

void* producer(void* arg)
{
	while(1)
	{
		sem_wait(&producer_sem);  //--  =0
		Node* node = (Node*)malloc(sizeof(Node));
		node->data = rand()%1000;
		node->next = head;
		head = node;

		printf("producer:%ld,%d\n",pthread_self(),node->data);

		sem_post(&customer_sem);   //customer_sem  ++

		sleep(rand()%5);
	}

	return NULL;
}

void* customer(void* arg)
{
	while(1)
	{	
		sem_wait(&customer_sem);   //0
		Node* del = head;
		head = head->next;
		printf("customer:%ld,%d\n",pthread_self(),del->data);
		free(del);

		sem_post(&producer_sem);   //producer  ++

		sleep(rand()%5);
	}

	return NULL;
}
int main()
{
	pthread_t thid[2];

	sem_init(&producer_sem,0,4);
	sem_init(&customer_sem,0,0);

	pthread_create(&thid[0],NULL,producer,NULL);
	pthread_create(&thid[1],NULL,customer,NULL);

	for(int i = 0;i < 2;i++)
	{
		pthread_join(thid[i],NULL);
	}

	sem_destroy(&producer_sem);
	sem_destroy(&customer_sem);

	return 0;
}

①先告诉你:这代码在干嘛?

  • 生产者:生产节点,插入链表
  • 消费者:消费节点,删除链表
  • 限制链表最多存 4 个节点(满了就不能生产)
  • 实现 :用 信号量 控制生产、消费的节奏

②先讲核心:什么是信号量?

信号量 = 一个计数器 + 等待队列

两个最核心操作:

  1. sem_wait( sem )

    • 计数器 -1
    • 如果计数器 < 0,线程阻塞等待
  2. sem_post( sem )

    • 计数器 +1
    • 如果有等待的线程,唤醒一个

③两个信号量的作用

复制代码
sem_t producer_sem;   // 表示"空闲位置",最多4个
sem_t customer_sem;   // 表示"已有产品数量",初始0
  • producer_sem = 4 → 链表最多放 4 个节点
  • customer_sem = 0 → 一开始链表空的,没有产品

④main函数初始化信号量

复制代码
sem_init(&producer_sem, 0, 4);
sem_init(&customer_sem, 0, 0);
  • 第 1 个参数:信号量变量
  • 第 2 个参数:0 = 线程间使用
  • 第 3 个参数:初始值

⑤生产者线程

复制代码
void* producer(void* arg)
{
	while(1)
	{
		sem_wait(&producer_sem); // 空闲位置 -1

sem_wait(&producer_sem)

  • 空闲位置 减 1

  • 如果减到 < 0 → 生产者阻塞(链表满了,不能再生产)

    复制代码
      	// 生产节点
      	Node* node = (Node*)malloc(sizeof(Node));
      	node->data = rand()%1000;
      	node->next = head;
      	head = node;
    
      	printf("producer:%ld,%d\n",pthread_self(),node->data);
    
      	sem_post(&customer_sem); // 产品数量 +1

sem_post(&customer_sem)

  • 产品数量 +1

  • 唤醒等待的消费者

    复制代码
      	sleep(rand()%5);
      }
      return NULL;

    }

⑥消费者线程

复制代码
void* customer(void* arg)
{
	while(1)
	{	
		sem_wait(&customer_sem); // 产品数量 -1

sem_wait(&customer_sem)

  • 产品数量 -1

  • 如果 < 0 → 消费者阻塞(链表空,没的消费)

    复制代码
      	// 消费(头删节点)
      	Node* del = head;
      	head = head->next;
      	printf("customer:%ld,%d\n",pthread_self(),del->data);
      	free(del);
    
      	sem_post(&producer_sem); // 空闲位置 +1

sem_post(&producer_sem)

  • 空闲位置 +1

  • 唤醒阻塞的生产者

    复制代码
      	sleep(rand()%5);
      }
      return NULL;

    }

⑦整段代码运行流程

初始状态

producer_sem = 4customer_sem = 0

第 1 步

消费者执行 sem_wait(customer)→ 0-1 = -1 → 阻塞等待

第 2 步

生产者生产sem_wait(producer) → 4-1=3生产完sem_post(customer) → 0+1=1

第 3 步

消费者被唤醒消费完sem_post(producer) → 3+1=4

第 4 步

如果生产者连续生产 4 次producer_sem 变成 0第 5 次生产时 sem_wait阻塞

⑧这个代码实现了什么?

  1. 链表最多存 4 个节点

  2. 满了,生产者就等

  3. 空了,消费者就等

  4. 生产一个,才能消费一个

  5. 完全用信号量实现同步

版本 输出特点 核心问题
无锁版本 生产、消费乱序,数字错乱、丢失 线程不安全,数据竞争
互斥锁 + 条件变量版本 生产一个、消费一个,严格交替,无连续生产 / 消费 缓存为 0,生产后必须等消费,效率低
信号量版本(当前) 可连续生产(最多 4 个)、连续消费,一一对应 带缓存的生产者 - 消费者,效率更高
相关推荐
HLC++12 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室13 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy15 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕16 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫17 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生18 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1119 小时前
linux基础IO
linux·运维·服务器
BelongPanda21 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯21 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983421 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器