多线程资源竞争的代码例子并附带解决方案

本文讨论了在C++中处理多线程共享全局变量时可能遇到的问题,通过互斥锁、原子操作、读写锁和条件变量等并发控制技术,展示了如何确保线程安全并优化性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如下代码可能得不到想要的value的值:

#include <iostream>
#include <thread>


int value = 0;   // 全局变量

void increment() {
    for (int i = 0; i < 1000; ++i) {
        ++value; // 更新全局变量
    }
}

void decrement() {
    for (int i = 0; i < 1000; ++i) {
        --value; // 更新全局变量
    }
}

int main() {
    std::thread t1(increment);  // 创建线程1
    std::thread t2(decrement);  // 创建线程2

    t1.join();  // 等待线程1完成
    t2.join();  // 等待线程2完成

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

    return 0;
}

解决方案1:使用互斥锁

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

std::mutex mtx; // 全局互斥锁
int value = 0;   // 全局变量

void increment() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 锁定互斥锁
        ++value; // 更新全局变量
    }
}

void decrement() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 锁定互斥锁
        --value; // 更新全局变量
    }
}

int main() {
    std::thread t1(increment);  // 创建线程1
    std::thread t2(decrement);  // 创建线程2

    t1.join();  // 等待线程1完成
    t2.join();  // 等待线程2完成

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

    return 0;
}

解决方案2:

原子操作: 使用C++11标准中的原子操作可以直接在内存中对数据进行原子操作,而不需要使用互斥锁。这适用于简单的赋值操作。

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> value(0); // 全局原子变量

void increment() {
    for (int i = 0; i < 1000; ++i) {
        ++value; // 原子性递增
    }
}

void decrement() {
    for (int i = 0; i < 1000; ++i) {
        --value; // 原子性递减
    }
}

int main() {
    std::thread t1(increment);  // 创建线程1
    std::thread t2(decrement);  // 创建线程2

    t1.join();  // 等待线程1完成
    t2.join();  // 等待线程2完成

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

    return 0;
}

解决方案3:读写锁,当读操作远多于写操作时,可以使用读写锁来提高性能。读写锁允许多个读线程同时访问资源,但写线程访问时会阻塞所有其他线程。

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

std::shared_mutex mtx; // 全局读写锁
int value = 0;          // 全局变量

void increment() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::shared_mutex> lock(mtx);
        ++value; // 更新全局变量
    }
}

void decrement() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::shared_mutex> lock(mtx);
        --value; // 更新全局变量
    }
}

int main() {
    std::thread t1(increment);  // 创建线程1
    std::thread t2(decrement);  // 创建线程2

    t1.join();  // 等待线程1完成
    t2.join();  // 等待线程2完成

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

    return 0;
}

解决方案4:条件变量: 当资源竞争涉及到特定的条件时,可以使用条件变量来协调线程的执行。

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

std::mutex mtx; // 全局互斥锁
std::condition_variable cv; // 全局条件变量
int value = 0;               // 全局变量

void increment() {
    for (int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        ++value; // 更新全局变量
        cv.notify_one(); // 通知等待的线程
    }
}

void decrement() {
    int expected = 0;
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        // 等待 value 增加
        cv.wait(lock, [&]{ return value > expected; });
        --value; // 更新全局变量
        expected = value; // 更新期望值
        lock.unlock();
        // ... 执行其他可能需要同步的操作
    }
}

int main() {
    std::thread t1(increment);  // 创建线程1
    std::thread t2(decrement);  // 创建线程2

    t1.join();  // 等待线程1完成
    t2.join();  // 等待线程2完成

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

    return 0;
}

decrement 函数使用 cv.wait 函数等待 value 增加。cv.wait 函数接受一个锁和一个lambda表达式作为条件。Lambda表达式返回一个布尔值,如果为真,则 cv.wait 返回 false,表示条件成立,线程继续执行。如果为假,则 cv.wait 返回 true,表示条件不成立,线程被阻塞。

请注意,这个例子中的条件变量使用是不太典型的,因为通常情况下,我们不会在一个无限循环中使用 cv.wait。这个例子只是用来展示如何使用条件变量来等待一个特定条件的发生。在实际应用中,条件变量通常用于更复杂的逻辑和更特定的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值