信号量机制

线程同步

多个线程可以并发执行,但由于资源有限,它们的执行往往是间断性的,进而导致线程以不可预知的速度推进,这就体现了线程的异步性。

异步执行的问题:例如,假设有两个线程A和B,分别负责读取和写入数据。理论上,写入操作应该在读取之前完成。但异步性可能导致读取操作先于写入发生,此时由于缓冲区尚未填充数据,读取线程A将无数据可读并因此被阻塞。

线程同步涉及协调多个并发线程,以确保在执行中按照特定顺序访问共享资源或执行相关的任务。数据读取必须在数据填充之后,这是一个同步过程。

线程互斥

由于线程的并发性,多个线程不可避免地需要同时访问共享资源,如打印机。如果同时发送打印命令,没有适当的管理,打印内容可能会混淆。

这就引入了线程互斥的概念,其目的是确保任何时刻只有一个线程能访问特定的共享资源。在这种情况下,打印机同时只允许一个线程访问,防止数据交叉和资源冲突。当线程 A 在访问打印机时,如果线程 B 也想要访问打印机,它就必须等待,直到 A线程访问结束并释放打印机资源后,B 线程才能去访问。

像上述的打印机这种在一个时间段内只允许一个线程使用的资源,称为临界资源,对临界资源进行访问的那段代码称为临界区

信号量与 PV 操作

可以通过系统提供的一对原语对信号量进行操作,实现线程的同步互斥

信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量)。

可以用一个信号量来表示系统中某种资源的数量。
eg:比如:系统中只有一台打印机,就可以设置一个初值为1的信号量

这一对原语为:
wait(S) signal(S)原语 S是信号量

wait(S)又称信号量的P操作,使计数器-- P(S)
signal(S)又称信号量的V操作,使计数器++V(S)

信号量的实现

#include <mutex>
#include <condition_variable>

class Semaphore {
private:
    std::mutex mutex_;
    std::condition_variable condition_;
    int count_;

public:
    Semaphore(int count = 0) : count_(count) {}

    void P() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ == 0) {
            condition_.wait(lock);
        }
        count_--;
    }

    void V() {
        std::unique_lock<std::mutex> lock(mutex_);
        count_++;
        condition_.notify_one();
    }
};

P 操作和 V 操作必须成对出现。缺少 P 操作就不能保证对临界资源的互斥访问,缺少 V 操作就会导致临界资源永远得不到释放、处于等待态的线程永远得不到唤醒。

实现线程互斥

  • 定义一个互斥信号量,并初始化为 1

  • 把对于临界资源的访问置于 P 操作和 V 操作之间

#include <iostream>
#include <thread>

Semaphore sem(1);

void task(int n) {
    sem.P();
    std::cout << "Thread " << n << " 进入临界区." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Thread " << n << " 离开临界区." << std::endl;
    sem.V();
}

int main() {
    // 直接创建每个线程
    std::thread t1(task, 1);
    std::thread t2(task, 2);
    std::thread t3(task, 3);
    std::thread t4(task, 4);
    std::thread t5(task, 5);

    // 分别加入每个线程
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();

    return 0;
}

实现线程同步

  • 定义一个同步信号量,并初始化为当前可用资源的数量

  • 在优先级较的操作的面执行 V 操作,释放资源

  • 在优先级较的操作的面执行 P 操作,申请占用资源

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

class Semaphore {
private:
    std::mutex mutex_;
    std::condition_variable condition_;
    int count_;

public:
    Semaphore(int count = 0) : count_(count) {}

    void wait() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ == 0) {
            condition_.wait(lock);
        }
        count_--;
    }

    void signal() {
        std::unique_lock<std::mutex> lock(mutex_);
        count_++;
        condition_.notify_one();
    }
};

Semaphore sem(0);

void funA() {
    sem.wait();
    std::cout << "执行funA" << std::endl;  //
}

void funB() {
    std::this_thread::sleep_for(std::chrono::seconds(1));  // Simulate work
    std::cout << "执行funB" << std::endl;  // Output before sending signal
    sem.signal();
}

int main() {
    std::thread t1(funA);
    std::thread t2(funB);
    t1.join();
    t2.join();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值