Linux\Unix线程的互斥锁和条件变量
互斥锁
互斥锁是线程之间最基本的同步形式,用于保护临界区,任意时刻只能有一个线程在临界区中执行。
初始化
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
mutex
:初始化锁的标识符attr
:锁的属性,如果设置为NULL
,则使用系统默认的
加锁
#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
mutex
:锁的标识符
lock
作用是给数据加锁,如果已经有线程给当前数据块加锁了,那么当前线程阻塞,直到上一个线程给代码解锁,然后当前线程唤醒,继续加锁。注意唤醒的过程是自动的,不需要写代码执行。
try_lock
是lock
的非阻塞形式,如果成功加锁,返回0;失败返回有关的错误码。
解锁
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
mutex
:锁的标识符
对加锁的数据进行解锁。
条件变量
经典的wait
和signal
操作,具体参照操作系统,在这里仅学习Linux\Unix中的操作。
初始化和销毁条件变量
#include <pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
cond
:条件变量的标识符attr
:条件变量的属性,设置为NULL
则使用系统默认的
wait操作
#include <pthread.h>int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,const struct timespec *abstime);
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
cond
:条件变量mutex
:互斥锁,需要进行wait
的代码片段abstime
:等待时间
signal操作
#include <pthread.h>int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
cond
:条件变量标识符
signal
表示唤醒一个阻塞的线程,broad_cast
表示唤醒所有的阻塞线程。如果唤醒一个,则根据线程优先级和有关的调度策略执行操作。
一些其它的
线程的属性、互斥量的属性、条件变量的属性可以通过有关的函数进行设置,具体参照手册。
代码实例
生产者线程向缓冲池中填充数据,消费者线程从缓冲区中读取数据。参照《Unix网络编程第二卷》,设计了一个新的结构。要明确,因为互斥量和锁必须同时出现,所以专门设计了一个结构Ready
用于wait
和signal
操作。但是生产者不用进行wait
和signal
操作,只需要添加货物的时候进行互斥,所以单独提取出来。需要注意的是,一定要记得解锁操作,否则会发生死锁阻塞。
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <random>
#include <queue>// 随机数引擎
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> disCargo(0, 20);
std::uniform_int_distribution<> disTime(0, 3);const int CONSUMER_NUM = 5;
const int PRODUCER_NUM = 3;
const int CARGO_NUM = 10;bool stop = false;std::vector<pthread_t> consumerThreads;
std::vector<pthread_t> producerThreads;// 生产者放置货物使用的互斥量
struct Cargo {pthread_mutex_t mutex;std::queue<int> buffer;
} cargoTag;// 消费者可以消费的条件变量
struct Ready {pthread_mutex_t mutex;pthread_cond_t cond;
} readyTag;void *consume(void *);
void *produce(void *);int main() {pthread_mutex_init(&cargoTag.mutex, nullptr);pthread_mutex_init(&readyTag.mutex, nullptr);pthread_cond_init(&readyTag.cond, nullptr);for (int i = 0; i < PRODUCER_NUM; ++i) {pthread_t num;pthread_create(&num, nullptr, &produce, &i);producerThreads.push_back(num);}for (int i = 0; i < CONSUMER_NUM; ++i) {pthread_t num;pthread_create(&num, nullptr, &consume, &i);consumerThreads.push_back(num);}for (const auto &it: producerThreads) {pthread_join(it, nullptr);}for (const auto &it: consumerThreads) {pthread_join(it, nullptr);}return 0;
}void *produce(void *arg) {pthread_t num = *(pthread_t *) arg;while (!stop) {int t = disTime(gen);int no = disCargo(gen);sleep(t); // 模拟生产使用的时间// 生产货物加锁,一定要注意顺序,防止出现死锁pthread_mutex_lock(&readyTag.mutex);pthread_mutex_lock(&cargoTag.mutex);printf("producer %ld produce cargo %d use %d s\n", (long) num, no, t);cargoTag.buffer.push(no);pthread_mutex_unlock(&cargoTag.mutex);pthread_mutex_unlock(&readyTag.mutex);pthread_cond_signal(&readyTag.cond); // 通知消费者}
}void *consume(void *arg) {pthread_t num = *(pthread_t *) arg;while (!stop) {pthread_mutex_lock(&readyTag.mutex);if (cargoTag.buffer.empty()) {pthread_mutex_unlock(&readyTag.mutex); // 一定要先解锁pthread_cond_wait(&readyTag.cond, &readyTag.mutex);} int no = cargoTag.buffer.front();cargoTag.buffer.pop();pthread_mutex_unlock(&readyTag.mutex); // 一定要解锁int t = disTime(gen);sleep(t);printf("consumer %ld consume cargo %d use %d s\n", (long) num, no, t);}
}
补充一个C++11的代码实例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <unistd.h>
#include <random>
#include <queue>
#include <signal.h>
#include <cstring>// 随机数引擎
std::random_device rd;
std::mt19937 gen (rd() );
std::uniform_int_distribution<> disCargo (0, 20);
std::uniform_int_distribution<> disTime (0, 3);std::vector<std::thread> producerThreads;
std::vector<std::thread> consumerThreads;struct Buffers {std::queue<int> buf;std::mutex mtx;
} buffer;std::mutex mtxCon;std::condition_variable condCon;bool stop = false;void produce (int id) {while (!stop) {int t = disTime (gen);int no = disCargo (gen);std::this_thread::sleep_for (std::chrono::duration<int, std::milli>(1000 * t));mtxCon.lock();buffer.mtx.lock();buffer.buf.push (no);buffer.mtx.unlock();mtxCon.unlock();condCon.notify_one(); // 唤醒一个消费者printf ("producer id %d generates cargo %d after %d seconds\n", id, t, no);}printf("producer %id stops............\n");
}void consume (int id) {while (!stop) {int no = 0;{std::unique_lock<std::mutex> lock (buffer.mtx);condCon.wait (lock, [&buffer]() {return !buffer.buf.empty();});no = buffer.buf.front();}buffer.buf.pop();int t = disTime(gen);printf("consumer id %d gets cargo %d and will sleep for %d seconds\n", id, no, t);std::this_thread::sleep_for (std::chrono::duration<int, std::milli>(1000 * t));}printf("consumer %id stops............\n");
}void handleSignal(int sig) {if (sig != SIGINT) {return;}puts("get signal SIGINT.........................");stop = true;
}int main() {struct sigaction sa;bzero(&sa, sizeof(sa));sa.sa_handler = handleSignal;sa.sa_flags = SA_RESTART;if (sigaction(SIGINT, &sa, nullptr) == -1) {perror("sigaction error\n");return 1;}for (int i = 0; i < 10; ++i) {producerThreads.emplace_back(std::thread(&produce, i));consumerThreads.emplace_back(std::thread(&consume, i));}for (auto &th: producerThreads) {th.join();}for (auto &th: consumerThreads) {th.join();}return 0;
}
Linux\Unix线程的互斥锁和条件变量相关推荐
- Linux下多线程编程互斥锁和条件变量的简单使用
Linux下的多线程遵循POSIX线程接口,称为pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,链接时需要使用库libpthread.a.线程是进程的一个实体,是CPU ...
- Linux C 多线程编程----互斥锁与条件变量-转
转:http://blog.csdn.net/xing_hao/article/details/6626223 一.互斥锁 互斥量从本质上说就是一把锁, 提供对共享资源的保护访问. 1. 初始化: 在 ...
- Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)
本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...
- linux线程(互斥锁、条件)
线程概念: 典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情.有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务. ...
- 非常精简的Linux线程池实现(一)——使用互斥锁和条件变量
https://blog.csdn.net/kxcfzyk/article/details/31719687 线程池的含义跟它的名字一样,就是一个由许多线程组成的池子. 有了线程池,在程序中使用多线程 ...
- linux线程间同步(1)互斥锁与条件变量
线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量以及读写锁. 互斥锁(mutex) 互斥锁,是一种信 ...
- Linux系统编程:使用mutex互斥锁和条件变量实现多个生成者和消费者模型
实现代码 如题,使用mutex互斥锁和条件变量实现多个生成者和消费者模型. 直接上代码,需要线程中的互斥锁和条件变量的相关知识进行支撑.这里就不细说了呀,代码中有一定的注释. #include < ...
- 信号量,互斥锁,条件变量的联系与区别
转自:http://blog.chinaunix.net/u3/108685/showart_2127853.html 信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程, ...
- 【C++】多线程互斥锁、条件变量
我们了解互斥量和条件变量之前,我们先来看一下为什么要有互斥量和条件变量这两个东西,了解为什么有这两东西之后,理解起来后面的东西就简单很多了!!! 先来看下面这段简单的代码: int g_num = 0 ...
最新文章
- 在linux命令行 下学习编写java
- html数据分析表格api_Python数据分析基本库——Matplotlib(一)
- android listview settag,Android View中setTag的二三事
- php编译自己库文件,php编译后追加库模块-gd库
- Python操作HDF5存储数据方法总结
- Linux下安装配置Jenkins
- MySql单表的curd-02
- NUMA - Non Uniform Memory Architecture 非统一内存架构
- 比Excel制图更强大,Python可视化工具Altair入门教程
- Java中HashMap和TreeMap的区别深入理解
- 苹果软件App上架问题
- paip.web service技术在 JAVA与.NET中的应用流程方案
- 用C++ Builder对图像进行特殊效果处理
- dialog下textarea滚动条不显示
- sscanf_s函数
- Java实现QQ机器人
- 走进CIM,开启智慧城市的全生命周期管理
- js 正则 验证密码输入,必须为6-15位,含有数字字母,或者符号
- 计算机二级word邀请函制作步骤,利用邮件合并制作邀请函(2)
- Andriod PDA RFID感应盘点
热门文章
- long类型转成integer类型避免空指针的方法_解决swagger的类型转换报错问题
- 渗透测试岗位面试题(渗透思路)
- 分拆素数和【筛选法】
- 对于electron-react-boilerplate(ERB)的学习笔记(legacy)
- tensorflow中的sequence_loss_by_example
- 获取北京时间授时api stm32 esp8266获取北京时间、年月日、星期api GMT格林威时间转换北京时间
- 动态规划,java实现算法导论15章钢条切割
- 区分PO,VO,DAO,BO,POJO
- 灭霸—个人冲刺(5)
- 随机初始化(代码实现)