如下代码可能得不到想要的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
。这个例子只是用来展示如何使用条件变量来等待一个特定条件的发生。在实际应用中,条件变量通常用于更复杂的逻辑和更特定的场景。