C++多线程

#include <iostream>           // std::cout
#include <thread>             // std::thread, std::this_thread::yield
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable

std::mutex mtx;
std::condition_variable cv;

int cargo = 0;
bool shipment_available() {return cargo!=0;}

void consume (int n) {
    for (int i=0; i<n; ++i) {
        std::unique_lock<std::mutex> lck(mtx);//自动上锁
        //第二个参数为false才阻塞(wait),阻塞完即unlock,给其它线程资源
        cv.wait(lck,shipment_available);
        // consume:
        std::cout << cargo << '\n';
        cargo=0;
    }
}

int main ()
{
    std::thread consumer_thread (consume,10);

    for (int i=0; i<10; ++i) {
        //每次cargo每次为0才运行。
        while (shipment_available()) std::this_thread::yield();
        std::unique_lock<std::mutex> lck(mtx);
        cargo = i+1;
        cv.notify_one();
    }

    consumer_thread.join();,
    return 0;
}

输出结果:

1
2
3
4
5
6
7
8
9
10

相应解释:

这段代码是一个使用C++标准库中的线程、互斥量和条件变量来实现生产者-消费者模型的例子。
在这个模型中,有一个生产者线程和一个消费者线程。生产者线程每次将一个数值(从1到10)赋值给全局变量cargo,然后通过条件变量cv通知消费者线程。消费者线程等待条件变量的通知,然后读取并打印cargo的值。
std::mutex mtx;定义了一个互斥量,用于保护共享数据cargo。std::condition_variable cv;定义了一个条件变量,用于在生产者和消费者之间进行通信。
consume函数是消费者线程的主体,它使用std::unique_lock和std::mutex来自动上锁和解锁。std::unique_lock的构造函数接受一个互斥量作为参数,并立即上锁。cv.wait(lck,shipment_available);会释放锁,并使线程阻塞,直到条件变量被通知或者shipment_available函数返回true。一旦条件满足,线程会重新获得锁并继续执行。
main函数首先创建了一个消费者线程,然后在主线程中生产数据。每次生产一个数值后,主线程会上锁,设置cargo的值,然后通过条件变量通知消费者线程。主线程使用std::this_thread::yield()来让出CPU,以便消费者线程有机会运行。
最后,主线程调用consumer_thread.join()来等待消费者线程结束,然后返回0。
这段代码的输出应该是数字1到10,每个数字一行。每个数字的顺序可能会有所不同,因为生产者和消费者线程的执行顺序取决于操作系统的调度。

二、线程特定数据(Thread Specific Data,简称TSD)

线程特定数据(Thread Specific Data,简称TSD)是一种在多线程环境中用于存储每个线程私有数据的机制。

在多线程环境中,全局变量和静态变量是所有线程共享的,这可能会导致数据的混乱和冲突。线程特定数据提供了一种方式,使得每个线程都可以有自己的私有数据,而不会影响其他线程。

在C++中,可以使用thread_local关键字来声明一个线程特定数据。这样,每个线程都会有一个独立的变量副本,而不是共享一个全局变量。

例如:

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

thread_local int threadVariable = 0;

std::mutex mtx;

void threadFunction() {
    threadVariable++;
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Thread " << std::this_thread::get_id() << " variable: " << threadVariable << std::endl;
}

int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}

输出为:

Thread 2 variable: 1
Thread 3 variable: 1

在这个例子中,threadVariable是一个线程特定数据,每个线程都有自己的threadVariable副本。当线程调用threadFunction时,它会递增自己的threadVariable,而不会影响其他线程的threadVariable

如果不用TSD,则测试如下:

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

int threadVariable = 0;

std::mutex mtx;

void threadFunction() {
    threadVariable++;
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Thread " << std::this_thread::get_id() << " variable: " << threadVariable << std::endl;
}

int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}

输出为:

Thread 2 variable: 2
Thread 3 variable: 2

三、多线程互斥锁来保护共享资源

以下是一个简单的多线程程序,展示了如何使用互斥锁来保护共享资源,确保线程安全。

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

std::mutex mtx;
int shared_resource = 0;

void increment_resource()
{
    for (int i = 0; i < 100000; i++) {
        mtx.lock();
        shared_resource++;
        mtx.unlock();
    }
}

void decrement_resource()
{
    for (int i = 0; i < 100000; i++) {
        mtx.lock();
        shared_resource--;
        mtx.unlock();
    }
}

int main()
{
    std::thread t1(increment_resource);
    std::thread t2(decrement_resource);

    t1.join();
    t2.join();

    std::cout << "Final value of shared_resource: " << shared_resource << std::endl;

    return 0;
}

输出结果为:

Final value of shared_resource: 0

在这个程序中,定义了一个共享资源shared_resource和一个互斥锁mtx

increment_resource函数和decrement_resource函数分别对shared_resource进行加1和减1操作,每个函数执行100000次。

在每次操作之前,都会先获取锁mtx,然后执行操作,最后释放锁。这样可以确保在任何时刻,只有一个线程可以访问shared_resource,从而避免数据竞争和不一致。

main函数中,创建了两个线程t1t2,分别运行increment_resourcedecrement_resource函数。然后等待这两个线程完成,最后输出shared_resource的最终值。

运行这个程序,你会发现shared_resource的最终值总是0,这证明了互斥锁的作用。如果没有使用互斥锁,shared_resource的最终值可能会不为0,因为两个线程可能会同时访问和修改shared_resource,导致数据竞争。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值