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 个)、连续消费,一一对应 带缓存的生产者 - 消费者,效率更高
相关推荐
程序猿编码39 分钟前
一个授予普通进程ROOT权限的Linux内核级后门:原理与实现深度解析
linux·运维·服务器·内核·root权限
小夏子_riotous43 分钟前
openstack的使用——9. 密钥管理服务Barbican
linux·运维·服务器·系统架构·centos·云计算·openstack
六点的晨曦2 小时前
VMware安装Ubuntu的记录
linux·ubuntu
w6100104662 小时前
CKA-2026-Service
linux·服务器·网络·service·cka
HXQ_晴天3 小时前
castor什么时候已有的 .cdh 数据可以直接用,不需要重新从 root 转换?
linux
Mapleay3 小时前
Ubuntu 源的重要性!之 libgmp-dev 无法安装
linux·服务器·windows
Benszen3 小时前
Linux容器:轻量级虚拟化革命
java·linux·运维
念恒123064 小时前
Linux初识
linux·服务器·c++
开开心心就好4 小时前
能把网页藏在Word里的实用摸鱼工具
linux·运维·服务器·windows·随机森林·逻辑回归·excel
Lucis__4 小时前
Linux网络:基于协议栈原理实现UDP通信
linux·网络·udp