linux线程间同步(互斥量与条件变量)
linux的线程有两个重要的同步方式。分别为互斥量(mutex)
和条件变量(condition variables)
.其中linux下互斥量功能类似RTOS下的互斥量。用于防止多个线程同时访问同一共享资源。而条件变量在共享资源发生变化时用来通知其他线程。互斥量与条件变量结合
使用时类似RTOS下的事件
。
互斥量(mutex)
linux的互斥量机制与RTOS下的互斥量机制一样。主要用于防止多个线程同时访问同一共享资源。
初始化条件变量时可以使用静态初始化和动态初始化:
静态初始化
:使用如pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
进行静态初始化。动态初始化
:需要用到pthread_mutex_init()
函数。动态初始化时可以设置互斥量的属性。使用结束后用pthread_mutex_destroy()进行相关资源释放。
互斥量涉及到的函数如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
- 动态初始化一个互斥量
- mutex:互斥量的句柄指针
- attr:互斥量的属性.NULL表示使用默认属性。
- return:if true:0. if false:大于0的错误码。
int pthread_mutex_destroy(pthread_mutex_t *mutex)
- 释放一个动态初始化的互斥量
- return:if true:0. if false:大于0的错误码。
int pthread_mutex_lock(pthread_mutex_t *mutex)
- 给互斥量上锁。如果互斥量已经上锁,则阻塞等待。
- mutex:要操作的互斥量
- return:if true:0. if false:大于0的错误码。
int pthread_mutex_unlock(pthread_mutex_t *mutex)
- 给互斥量解锁.
- return:if true:0. if false:大于0的错误码。
int pthread_mutex_trylock(pthread_mutex_t *mutex)
- 尝试给互斥量上锁。如果互斥量已经上锁,则返回错误码EBUSY。
- return:if true:0. if false:大于0的错误码。
- EBUSY:互斥量已经上锁。
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime)
- 给互斥量上锁。如果互斥量已经上锁,则阻塞等待。超过设置时间时,返回错误码ETIMEDOUT。
- abstime:绝对时间。
- return:if true:0. if false:大于0的错误码。
- ETIMEDOUT.:超时。
静态初始化互斥量使用例程如下:
#include <pthread.h>
#include <stdio.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
//定义全局变量,用来代表共享资源
static int share_num = 0;
//1. 定义并初始化静态互斥量
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
void *thread_entry(void *arg)
{
int num = 0;
int count = *((int *)arg);
for (int i = 0; i < count; i++){
//2. 为共享资源上锁
if( pthread_mutex_lock(&mtx) != 0){
printf("mutex_lock error.");
}
num = share_num;
num++;
share_num = num;
//3. 为共享资源解锁
if(pthread_mutex_unlock(&mtx) != 0){
printf("mutex_unlock error.");
}
}
return NULL;
}
void main(void)
{
pthread_t t1, t2;
int counts = 20000;
if(pthread_create(&t1, NULL, thread_entry, &counts) != 0){
printf("thread t1 create error.");
exit(1);
}
if(pthread_create(&t2, NULL, thread_entry, &counts) != 0){
printf("thread t2 create error.");
exit(1);
}
if(pthread_join(t1, NULL) != 0){
printf("pthread_join t1 error.");
exit(1);
}
if(pthread_join(t2, NULL) != 0){
printf("pthread_join t2 error.");
exit(1);
}
printf("share_num:%d\n",share_num);
exit(0);
}
条件变量(condition variables)
互斥量防止多个线程同时访问同一共享资源。而条件变量
一般在共享资源发生变化时用来通知其他线程。它使用时依赖互斥量。互斥量与条件变量的组合使用可以方便的实现RTOS中的事件机制。
初始化条件变量时可以使用静态初始化和动态初始化:
静态初始化
:使用如pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
进行静态初始化。动态初始化
:需要用到pthread_cond_init()
函数。动态初始化时可以设置条件变量的属性。使用结束后用pthread_cond_destroy()进行相关资源释放。
条件变量的相关函数介绍如下:
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
- 动态的初始化一个条件变量。
- cond:返回的初始化好的条件变量指针
- attr:用于条件变量相关的属性设置指针
- return:if true:0. if false:大于0的错误码。
- ENOMEM:内存不足
int pthread_cond_destroy(pthread_cond_t *cond)
- 释放一个动态初始化的条件变量。
- return:if true:0. if false:大于0的错误码。
int pthread_cond_signal(pthread_cond_t *cond)
- 保证唤醒至少一条因等待条件变量而阻塞的线程.
- return:if true:0. if false:大于0的错误码。
int pthread_cond_broadcast(pthread_cond_t *cond)
- 唤醒所有因等待条件变量而阻塞的线程.
- return:if true:0. if false:大于0的错误码。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
- 使线程进入阻塞等待状态。直到接收到相应的条件变量信号。
- mutex:和条件变量配合使用的互斥量。
- return:if true:0. if false:大于0的错误码。
- 注意:此函数与互斥量配合使用。在pthread_mutex_lock()与pthread_mutex_unlock()之间使用。此函数内部逻辑为:首先解锁互斥量。然后阻塞当前线程直到其他线程调用pthread_cond_signal()发送信号。最后从新锁定互斥量。
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,const struct timespec *abstime)
- 使用类似pthread_cond_wait()函数。增加了最长等待时间。
- return:if true:0. if false:大于0的错误码。
- ETIMEOUT:超时
下面使用一个生产者-消费者的例程来展示条件变量的使用:
#include <pthread.h>
#include <stdio.h>
#include <error.h>
#include <stdlib.h>
#include <unistd.h>
/* 模拟共享资源 */
#define BUFF_MAX 512
static int share_num = 0;
static int share_buff[BUFF_MAX] = {0};
/* 1.静态初始化互斥量与条件变量 */
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
/* 生产者线程 */
void *produce_entry(void *arg)
{
printf("thread produce runing.\n");
int count = 0;
while(1){
//2. 为共享资源上锁
if( pthread_mutex_lock(&mtx) != 0){
printf("mutex_lock error.");
}
// 操作共享资源
if(share_num < BUFF_MAX){
share_buff[share_num] = count++;
share_num ++;
}
//3. 为共享资源解锁
if(pthread_mutex_unlock(&mtx) != 0){
printf("mutex_unlock error.");
}
printf("produce cond_signal.\n");
//4. 发送条件变量信号
pthread_cond_signal(&cond);
sleep(1);
}
return NULL;
}
void *consumer_entry(void *arg)
{
printf("thread consumer runing.\n");
while(1){
//1. 为共享资源上锁
if( pthread_mutex_lock(&mtx) != 0){
printf("mutex_lock error.");
}
//2. 循环等待条件变量
while (share_num <= 0){
pthread_cond_wait(&cond, &mtx);
}
share_num --;
printf("share_value:%d \n",share_buff[share_num]);
//3. 为共享资源解锁
if(pthread_mutex_unlock(&mtx) != 0){
printf("mutex_unlock error.");
}
}
return NULL;
}
void main(void)
{
pthread_t t1, t2;
if(pthread_create(&t1, NULL, produce_entry, NULL) != 0){
printf("thread t1 create error.");
exit(1);
}
if(pthread_create(&t2, NULL, consumer_entry, NULL) != 0){
printf("thread t2 create error.");
exit(1);
}
printf("thread create ok.\n");
if(pthread_join(t1, NULL) != 0){
printf("pthread_join t1 error.");
exit(1);
}
if(pthread_join(t2, NULL) != 0){
printf("pthread_join t2 error.");
exit(1);
}
exit(0);
}
关于技术交流
此处后的文字已经和题目内容无关,可以不看。
qq群:825695030
微信公众号:嵌入式的日常
如果上面的文章对你有用,欢迎打赏、点赞、评论。