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_locklock的非阻塞形式,如果成功加锁,返回0;失败返回有关的错误码。

解锁

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • mutex:锁的标识符
    对加锁的数据进行解锁。

条件变量

经典的waitsignal操作,具体参照操作系统,在这里仅学习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用于waitsignal操作。但是生产者不用进行waitsignal操作,只需要添加货物的时候进行互斥,所以单独提取出来。需要注意的是,一定要记得解锁操作,否则会发生死锁阻塞。

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值