linux线程间同步(互斥量与条件变量)

linux线程间同步(互斥量与条件变量)

linux的线程有两个重要的同步方式。分别为互斥量(mutex)条件变量(condition variables).其中linux下互斥量功能类似RTOS下的互斥量。用于防止多个线程同时访问同一共享资源。而条件变量在共享资源发生变化时用来通知其他线程。互斥量与条件变量结合使用时类似RTOS下的事件

互斥量(mutex)

linux的互斥量机制与RTOS下的互斥量机制一样。主要用于防止多个线程同时访问同一共享资源。

初始化条件变量时可以使用静态初始化和动态初始化:

  1. 静态初始化:使用如pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;进行静态初始化。
  2. 动态初始化:需要用到pthread_mutex_init()函数。动态初始化时可以设置互斥量的属性。使用结束后用pthread_mutex_destroy()进行相关资源释放。

互斥量涉及到的函数如下:

  1. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
    1. 动态初始化一个互斥量
    2. mutex:互斥量的句柄指针
    3. attr:互斥量的属性.NULL表示使用默认属性。
    4. return:if true:0. if false:大于0的错误码。
  2. int pthread_mutex_destroy(pthread_mutex_t *mutex)
    1. 释放一个动态初始化的互斥量
    2. return:if true:0. if false:大于0的错误码。
  3. int pthread_mutex_lock(pthread_mutex_t *mutex)
    1. 给互斥量上锁。如果互斥量已经上锁,则阻塞等待。
    2. mutex:要操作的互斥量
    3. return:if true:0. if false:大于0的错误码。
  4. int pthread_mutex_unlock(pthread_mutex_t *mutex)
    1. 给互斥量解锁.
    2. return:if true:0. if false:大于0的错误码。
  5. int pthread_mutex_trylock(pthread_mutex_t *mutex)
    1. 尝试给互斥量上锁。如果互斥量已经上锁,则返回错误码EBUSY。
    2. return:if true:0. if false:大于0的错误码。
      1. EBUSY:互斥量已经上锁。
  6. int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime)
    1. 给互斥量上锁。如果互斥量已经上锁,则阻塞等待。超过设置时间时,返回错误码ETIMEDOUT。
    2. abstime:绝对时间。
    3. return:if true:0. if false:大于0的错误码。
      1. 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中的事件机制。

初始化条件变量时可以使用静态初始化和动态初始化:

  1. 静态初始化:使用如pthread_cond_t cond = PTHREAD_COND_INITIALIZER;进行静态初始化。
  2. 动态初始化:需要用到pthread_cond_init()函数。动态初始化时可以设置条件变量的属性。使用结束后用pthread_cond_destroy()进行相关资源释放。

条件变量的相关函数介绍如下:

  1. int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
    1. 动态的初始化一个条件变量。
    2. cond:返回的初始化好的条件变量指针
    3. attr:用于条件变量相关的属性设置指针
    4. return:if true:0. if false:大于0的错误码。
      1. ENOMEM:内存不足
  2. int pthread_cond_destroy(pthread_cond_t *cond)
    1. 释放一个动态初始化的条件变量。
    2. return:if true:0. if false:大于0的错误码。
  3. int pthread_cond_signal(pthread_cond_t *cond)
    1. 保证唤醒至少一条因等待条件变量而阻塞的线程.
    2. return:if true:0. if false:大于0的错误码。
  4. int pthread_cond_broadcast(pthread_cond_t *cond)
    1. 唤醒所有因等待条件变量而阻塞的线程.
    2. return:if true:0. if false:大于0的错误码。
  5. int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
    1. 使线程进入阻塞等待状态。直到接收到相应的条件变量信号。
    2. mutex:和条件变量配合使用的互斥量。
    3. return:if true:0. if false:大于0的错误码。
    4. 注意:此函数与互斥量配合使用。在pthread_mutex_lock()与pthread_mutex_unlock()之间使用。此函数内部逻辑为:首先解锁互斥量。然后阻塞当前线程直到其他线程调用pthread_cond_signal()发送信号。最后从新锁定互斥量。
  6. int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,const struct timespec *abstime)
    1. 使用类似pthread_cond_wait()函数。增加了最长等待时间。
    2. return:if true:0. if false:大于0的错误码。
      1. 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
微信公众号:嵌入式的日常
如果上面的文章对你有用,欢迎打赏、点赞、评论。二维码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

theboynoName

感谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值