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

Linux系统编程多线程之条件变量和信号量讲解

一.前言

生产者消费者模型引入

/*简单的生产者消费者模型
如何查看错误:ulimit -a发现core file size              (blocks, -c) 0生成core文件ulimit -c unlimitedgcc producust.c -o pro -lpthread -g编译后产生段错误发现没有生成core文件cat /proc/sys/kernel/core_pattern如果输出的是一个路径(例如 /var/crash/core.%e.%p),核心文件可能会保存在指定的位置,而不是当前工作目录设置核心文件始终生成在当前目录sudo sysctl -w kernel.core_pattern=core再次运行pro,即生成core文件
*/
/*生产者消费者模型(粗略的版本)
*/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>struct Node{int num;struct Node *next;
};//创建互斥量
pthread_mutex_t mutex;
// 头结点
struct Node * head = NULL;void * producer(void * arg) {// 不断的创建新的节点,添加到链表中while(1) {pthread_mutex_lock(&mutex);struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));newNode->next = head;head = newNode;newNode->num = rand() % 1000;printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());pthread_mutex_unlock(&mutex);usleep(100);}return NULL;
}void * customer(void * arg) {while(1) {pthread_mutex_lock(&mutex);// 保存头结点的指针struct Node * tmp = head;if(head!=NULL){head = head->next;printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());free(tmp);pthread_mutex_unlock(&mutex);usleep(100);}else{pthread_mutex_unlock(&mutex);}}return  NULL;
}int main() {pthread_mutex_init(&mutex,NULL);// 创建5个生产者线程,和5个消费者线程pthread_t ptids[5], ctids[5];for(int i = 0; i < 5; i++) {pthread_create(&ptids[i], NULL, producer, NULL);pthread_create(&ctids[i], NULL, customer, NULL);}for(int i = 0; i < 5; i++) {pthread_detach(ptids[i]);pthread_detach(ctids[i]);}while(1){sleep(10);}pthread_mutex_destroy(&mutex);pthread_exit(NULL);return 0;
}

二.条件变量

 

条件变量不是锁,只是配合我们的互斥锁去使用

条件变量的类型:pthread_cond_t

初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t*restrict attr);

销毁
int pthread_cond_destroy(pthread_cond_t*cond);

一直等待,并且需要通知解除
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex);

等待多长的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t*restrict mutex,const struct timespec *restrict abstime);

唤醒一个或多个等待
int pthread_cond_signal(pthread_cond_t*cond);

唤醒所有的
int pthread_cond_broadcast(pthread_cond_t*cond);

案例示范

/*
初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t*restrict attr);销毁
int pthread_cond_destroy(pthread_cond_t*cond);一直等待,并且需要通知解除
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex);等待多长的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t*restrict mutex,const struct timespec *restrict abstime);唤醒一个或多个等待
int pthread_cond_signal(pthread_cond_t*cond);唤醒所有的
int pthread_cond_broadcast(pthread_cond_t*cond);
*/#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>struct Node{int num;struct Node *next;
};//创建互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;
// 头结点
struct Node * head = NULL;void * producer(void * arg) {// 不断的创建新的节点,添加到链表中while(1) {pthread_mutex_lock(&mutex);struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));newNode->next = head;head = newNode;newNode->num = rand() % 1000;printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());//只要生产一个就通知消费者进行消费pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);usleep(100);}return NULL;
}void * customer(void * arg) {while(1) {pthread_mutex_lock(&mutex);// 保存头结点的指针struct Node * tmp = head;if(head!=NULL){head = head->next;printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());free(tmp);pthread_mutex_unlock(&mutex);usleep(100);}else{//没有数据,阻塞等待//当wait这个函数调用阻塞时,会对这个互斥锁进行解锁,当不阻塞时会对这个互斥锁重新加锁pthread_cond_wait(&cond,&mutex);pthread_mutex_unlock(&mutex);}}return  NULL;
}int main() {pthread_mutex_init(&mutex,NULL);pthread_cond_init(&cond,NULL);// 创建5个生产者线程,和5个消费者线程pthread_t ptids[5], ctids[5];for(int i = 0; i < 5; i++) {pthread_create(&ptids[i], NULL, producer, NULL);pthread_create(&ctids[i], NULL, customer, NULL);}for(int i = 0; i < 5; i++) {pthread_detach(ptids[i]);pthread_detach(ctids[i]);}while(1){sleep(10);}pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);pthread_exit(NULL);return 0;
}

三.信号量

信号量:也是用于阻塞线程的
灯亮可以用,灯灭不可以用,不可以保证多线程数据安全问题,若需要保证,需要跟互斥锁一起使用

信号量的类型 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);

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);

 示范代码

/*
初始化
int sem_init(sem_t*sem,int pshared, unsigned int value);-参数:sem:信号量pshared:代表用在线程(0)之间还是进程(其他值)之间value:信号量中的值释放资源
int sem_destroy(sem_t*sem);等待
int sem_wait(sem_t*sem);-没调用一次对信号量值-1,若剩下的值=0阻塞,>0直接返回,调用post+1int sem_trywait(sem_t*sem);等待多长时间
int sem_timedwait(sem_t*sem,const struct timespec *abs_timeout);解锁信号量
int sem_post(sem_t*sem);-没调用一次对信号量+1int sem_getvalue(sem_t*sem,int*sval);
*/
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>struct Node{int num;struct Node *next;
};//创建互斥量
pthread_mutex_t mutex;//创建两个信号量
sem_t psem,csem;// 头结点
struct Node * head = NULL;void * producer(void * arg) {// 不断的创建新的节点,添加到链表中while(1) {sem_wait(&psem);pthread_mutex_lock(&mutex);struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));newNode->next = head;head = newNode;newNode->num = rand() % 1000;printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());pthread_mutex_unlock(&mutex);sem_post(&csem);usleep(100);}return NULL;
}void * customer(void * arg) {while(1) {sem_wait(&csem);pthread_mutex_lock(&mutex);// 保存头结点的指针struct Node * tmp = head;head = head->next;printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());free(tmp);pthread_mutex_unlock(&mutex);sem_post(&psem);}return  NULL;
}int main() {sem_init(&psem,0,8);sem_init(&csem,0,0);pthread_mutex_init(&mutex,NULL);// 创建5个生产者线程,和5个消费者线程pthread_t ptids[5], ctids[5];for(int i = 0; i < 5; i++) {pthread_create(&ptids[i], NULL, producer, NULL);pthread_create(&ctids[i], NULL, customer, NULL);}for(int i = 0; i < 5; i++) {pthread_detach(ptids[i]);pthread_detach(ctids[i]);}while(1){sleep(10);}pthread_mutex_destroy(&mutex);pthread_exit(NULL);return 0;
}


http://www.mrgr.cn/news/75160.html

相关文章:

  • 真正的一站式视频出海解决方案
  • 关于Unity使用LookAt时为什么不能旋转
  • AI 大模型应用:AI开发的捷径工作流模式
  • Springboot 微信小程序定位后将坐标转换为百度地图坐标,在百度地图做逆地址解析
  • 简析大模型参数高效微调方法
  • 华为私有接口类型hybrid
  • java八股-垃圾回收机制-垃圾回收算法,分代回收,垃圾回收器
  • 精灵图(十八课)
  • RHCE web解析、dns配置、firewalld配置实验
  • 人工智能技术的发展历程和现状
  • 基于Spring Boot+Vue的多媒体素材管理系统的设计与实现
  • 多模态Embedding不愧是CVPR和NIPS的共同选择!这发文思路真的需要好好学习一下!
  • c语言学习16按键控制流水灯
  • 闯关leetcode——3178. Find the Child Who Has the Ball After K Seconds
  • docker安装到D盘
  • 游戏引擎学习第11天
  • 易考八股文之代理模式在AOP中如何应用?
  • Gartner发布XDR扩展检测和响应市场指南:XDR需要具备的19项功能
  • 逆向攻防世界CTF系列31-elrond32
  • 代码随想录算法训练营第46天 | 647. 回文子串、516.最长回文子序列
  • curl 安装最新版
  • 如何在手机上完整下载B站视频并保存到相册?
  • 制造业数字化转型路线图,终于有人捋清楚了
  • 用哈希表封装myunordered_map/_set--C++
  • 《Python网络安全项目实战》项目5 编写网站扫描程序
  • 20241113下载安装虚拟桌面工具VYSOR并连接中科创达的高通CM6125开发板