当前位置: 首页 > news >正文

Linux-信号量

文章目录

  • 信号量
    • 概述
    • 信号量相关函数
      • sem_init函数
      • sem_destroy函数
      • sem_wait 信号量P操作(减1)
      • sem_post信号量V操作(加1)
      • gem_getvalue 获取信号量的值
    • 练习一
    • 练习二
    • 练习三

信号量

概述

信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。

编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。

PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。

信号量主要用于进程或线程间的同步和互斥这两种典型情况。

信号量数据类型为:sem_t。

信号量用于互斥:

在这里插入图片描述
信号量用于同步:
在这里插入图片描述

信号量相关函数

sem_init函数

#include <semaphore.h>
​
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。
参数:sem:信号量的地址。pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。value:信号量的初始值。
返回值:成功:0失败: - 1

sem_destroy函数

#include <semaphore.h>
​
int sem_destroy(sem_t *sem);
功能:删除 sem 标识的信号量。
参数:sem:信号量地址。
返回值:成功:0失败: - 1
​

sem_wait 信号量P操作(减1)

#include <semaphore.h>
​
int sem_wait(sem_t *sem);
功能:将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。
参数:sem:信号量的地址。
返回值:成功:0失败: - 1
​
int sem_trywait(sem_t *sem);以非阻塞的方式来对信号量进行减 1 操作。若操作前,信号量的值等于 0,则对信号量的操作失败,函数立即返回。
​
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);限时尝试将信号量的值减 1abs_timeout:绝对时间

abs_timeout补充说明:

struct timespec {
time_t tv_sec; /* seconds / // 秒
long tv_nsec; /
nanosecondes*/ // 纳秒
}

time_t cur = time(NULL); //获取当前时间。
struct timespec t; //定义timespec 结构体变量t
t.tv_sec = cur + 1; // 定时1秒
sem_timedwait(&cond, &t);

sem_post信号量V操作(加1)

#include <semaphore.h>
​
int sem_post(sem_t *sem);
功能:将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。
参数:sem:信号量的地址。
返回值:成功:0失败:-1

gem_getvalue 获取信号量的值

#include <semaphore.h>
​
int sem_getvalue(sem_t *sem, int *sval);
功能:获取 sem 标识的信号量的值,保存在 sval 中。
参数:sem:信号量地址。sval:保存信号量值的地址。
返回值:成功:0失败:-1

练习一

信号量实现打印机效果

#include <stdio.h>
#include <string.h> 
#include <stdlib.h> #include <semaphore.h>
#include <pthread.h>
#include <unistd.h>sem_t sem;void print(const char *str)
{while(*str){printf("%c", *str);fflush(stdout);str++;usleep(50000);}
}void *PrintA(void *arg)
{//申请资源sem_wait(&sem);print("hello");//释放资源sem_post(&sem);pthread_exit(NULL);
}
void *PrintB(void *arg)
{sem_wait(&sem);print("world");sem_post(&sem);pthread_exit(NULL);
}
int test01()
{int ret = -1;pthread_t tid1 = -1;pthread_t tid2 = -1;ret = sem_init(&sem, 0, 1);if(0 != ret){printf("sem_init failed\n");goto err0;}ret = pthread_create(&tid1, NULL, PrintA, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}ret = pthread_create(&tid2, NULL, PrintB, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}pthread_join(tid1, NULL);pthread_join(tid2, NULL);sem_destroy(&sem);printf("\n");return 0;
err0:return 1;}

练习二

#include <stdio.h>
#include <string.h> 
#include <stdlib.h> #include <unistd.h>
#include <pthread.h>
#include <semaphore.h>//表示可以存放产品的容器
sem_t sem_producer;//表示可以消费产品的个数
sem_t sem_customer;pthread_mutex_t mutex;typedef struct _node_t
{int data;struct _node_t *next;
}node_t;node_t *head = NULL;//生产者
void *producer(void *arg)
{node_t *new = NULL;while(1){//申请资源 ,存放产品的容器sem_wait(&sem_producer);pthread_mutex_lock(&mutex);new = malloc(sizeof(node_t));if(NULL == new){printf("malloc failed\n");pthread_mutex_unlock(&mutex);break;}memset(new, 0, sizeof(node_t));new->data = random() % 100 + 1;new->next = head;head = new;printf("-------生产者生产了产品 %d\n", new->data);pthread_mutex_unlock(&mutex);//可以卖的产品个数加1sem_post(&sem_customer);sleep(random() % 3 + 1);}pthread_exit(NULL);
}
//消费者
void *customer(void *arg)
{node_t *tmp = NULL;while(1){//申请资源,产品的个数sem_wait(&sem_customer);pthread_mutex_lock(&mutex);//删除链表第一个节点tmp = head;head = head->next;printf("消费者消费产品 %d\n", tmp->data);free(tmp);pthread_mutex_unlock(&mutex);//释放资源,容器的个数sem_post(&sem_producer);sleep(random() % 3 + 1);}pthread_exit(NULL);
}
int test01()
{int ret = -1;pthread_t tid1 = -1;pthread_t tid2 = -1;srandom(time(NULL));ret = sem_init(&sem_producer, 0, 4);if(0 != ret){printf("sem_init failed\n");goto err0;}   ret =sem_init(&sem_customer, 0, 0);if(0 != ret){printf("sem_init failed\n");goto err0;}ret = pthread_mutex_init(&mutex, NULL);if(0 != ret){printf("pthread_mutex_init failed\n");goto err0;}//生产者线程ret = pthread_create(&tid1, NULL, producer, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}//消费者线程ret = pthread_create(&tid1, NULL, customer, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&mutex);sem_destroy(&sem_producer);sem_destroy(&sem_customer);return 0;
err0:return 1;
}

练习三

哲学家吃饭

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
​
pthread_mutex_t mutex[5];void* dine(void* arg)
{int num = (int)arg;int left, right;if(num < 4){// 前4个人,右手拿自己筷子right = num;left = num+1;}else if(num == 4){// 最后一个人,右手拿别人筷子right = 0;left = num;}// 吃饭while(1){// 右手加锁pthread_mutex_lock(&mutex[right]);// 尝试抢左手筷子if(pthread_mutex_trylock(&mutex[left]) == 0){// 吃面。。。printf("%c 正在吃面。。。。。。\n", num+'A');// 吃完放筷子pthread_mutex_unlock(&mutex[left]);}// 解锁pthread_mutex_unlock(&mutex[right]);sleep(rand()%5);}
}int main(int argc, const char* argv[])
{pthread_t p[5];for(int i=0; i<5; ++i){pthread_mutex_init(&mutex[i], NULL);}for(int i=0; i<5; ++i){pthread_create(&p[i], NULL, dine, (void*)i);}for(int i=0; i<5; ++i){pthread_join(p[i], NULL);}for(int i=0; i<5; ++i){pthread_mutex_destroy(&mutex[i]);}return 0;
}

文章转载自:

http://2a6C5Vsl.njntp.cn
http://yg2SodYy.njntp.cn
http://aJRhkcVL.njntp.cn
http://mmdWlJ3Z.njntp.cn
http://48D5U1hV.njntp.cn
http://vDZPQEuQ.njntp.cn
http://c4xbH2Uv.njntp.cn
http://uakkQdO0.njntp.cn
http://IN9J16k2.njntp.cn
http://fJq3Y769.njntp.cn
http://G8wgaLey.njntp.cn
http://P07MYHyK.njntp.cn
http://PKC4EBYT.njntp.cn
http://AzFV4Mk8.njntp.cn
http://BCWIDCTO.njntp.cn
http://U442KU5C.njntp.cn
http://vfnD8hg7.njntp.cn
http://gTFxpNYr.njntp.cn
http://BavieC7x.njntp.cn
http://It5b3yah.njntp.cn
http://XaOPSWhe.njntp.cn
http://8C0i5BjN.njntp.cn
http://Qs6AZGNw.njntp.cn
http://qep6pIsW.njntp.cn
http://ehbHHPB2.njntp.cn
http://ga1lo1MI.njntp.cn
http://Fy9E9XHn.njntp.cn
http://ESkBmNnp.njntp.cn
http://qvUL3mRq.njntp.cn
http://tYzEBZe2.njntp.cn
http://www.dtcms.com/a/374016.html

相关文章:

  • 3000h CeB₆ 灯丝加持的 Phenom XL G3 扫描电镜技术亮点
  • C语言scanf函数的空格问题
  • 【Git】使用GitCode的全局配置
  • 论文阅读:ACL 2023 MEETINGQA: Extractive Question-Answering on Meeting Transcripts
  • Docker Compose healthcheck介绍(监控容器中服务的实际健康状态)数据库健康检查pg_isready
  • 鸿蒙NEXT中SQLite数据库全面实战指南
  • Go语言文件处理实战指南
  • 【鸿蒙(openHarmony)ETS语言实现视频播放器的详细步骤】
  • SpringBoot教程(三十一) | SpringBoot集成SpringSecurity权限框架
  • 第四十九篇-Tesla P40+Fastllm+Hunyuan-A13B-Instruct+CPU+GPU混合部署推理
  • 安装docker遇到的问题1: [Errno 14] curl#35 - “TCP connection reset by peer“
  • 【Debug日志 | 模型loss不降】
  • 千呼万唤始出来 谭维维音乐会官宣北京
  • 如何给智能家居注入“温度”?世强详解无线通信与AI算力背后的创新方案​
  • 金智维的智能财务管理工具有哪些?
  • 嵌入式 - ARM(1):ARM体系结构
  • 关于对鱼眼相机图片进行畸变校正的两种思路
  • mybatis-plus原生的批量插入
  • 设计模式 概述
  • SQL 注入与防御-第九章:平台层防御
  • SCADA与DCS深度集成实践:打破工厂“信息孤岛”,让实时控制更智能
  • 小学挫折教育主题班会PPT课件模板下载
  • 深入理解 MyBatis-Plus 的 `BaseMapper`
  • YOLOv8 TensorRT C++部署实战详解:从XMake构建到推理流水线
  • HTML HTML基础(3)
  • 几何动点问题
  • C++从字符串中移除前导零
  • PPP PRIVATE NETWORK™ 2 企业级虚拟以太网接入综合解决方案介绍
  • 《会“偷听”的石头:声流石的震撼发现》
  • 线程的控制(互斥+同步)