C++ 线程间的互斥和通信场景分析
简介
多线程编程可以在程序中实现并发,提高程序的执行效率。但是却会导致一些线程安全问题,如数据竞争、死锁等。因此,需要采取一些方法来解决多线程并发导致的问题,如互斥和通信。
本文将介绍C++中线程间互斥和通信的相关概念和方法,以及场景分析,解决该问题的最佳实践。
互斥
在多线程环境下,多个线程可能同时访问共享变量,导致数据竞争的问题。互斥可以解决这个问题。
Mutex
Mutex全称为互斥量,是一种同步对象,用于保护共享资源不被多个线程同时访问。C++11中提供了标准库的mutex类。
使用方法如下:
#include <mutex>
//创建mutex对象
std::mutex mu;
//加锁
mu.lock();
//解锁
mu.unlock();
//使用unique_lock实现自动加锁和解锁
std::unique_lock<std::mutex> l(mu);
Lock_guard
Lock_guard是一个RAII风格的互斥量,可以保证资源的释放,从而避免了资源泄漏和死锁的问题。
使用方法如下:
#include <mutex>
std::mutex mu;
{
std::lock_guard<std::mutex> lock(mu);
// critical section
}
Mutex使用场景分析
以下是一个模拟银行账户的示例,假设一个账户有1000元钱,两个人A和B同时去ATM机上取钱,如果没有互斥,可能导致账户余额不正确。
//模拟银行账户
int account_balance = 1000;
void withdraw(int amount)
{
//互斥保护临界区
std::lock_guard<std::mutex> lock(mu);
if(amount <= account_balance)
{
account_balance -= amount;
std::cout << "withdraw successful, balance:" << account_balance << std::endl;
}
else
{
std::cout << "withdraw failed, balance:" << account_balance << std::endl;
}
}
int main()
{
std::thread t1(withdraw, 700);
std::thread t2(withdraw, 500);
t1.join();
t2.join();
return 0;
}
通信
多线程通信不仅涉及到互斥,还需要消息传递和同步的机制。
条件变量
Condition_variable
条件变量用于一些条件控制的场合,一个线程不停地检测某种条件变量实际的值是否满足自己的要求,这样既浪费了cpu时间,也浪费了内存。用条件变量可以解决这个问题,让一个正在等待上述条件的线程先睡眠,当条件达成时再被唤醒。
使用方法如下:
#include <condition_variable>
std::mutex mu;
std::queue<int> q;
std::condition_variable cond;
void producer()
{
for(int i = 0; i < 10; ++i)
{
std::unique_lock<std::mutex> locker(mu);
q.push(i);
std::cout << "Pushing value:" << i << std::endl;
locker.unlock();
cond.notify_one();
}
}
void consumer()
{
while(true)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [](){ return !q.empty(); });
int val = q.front();
q.pop();
std::cout << "Get value: " << val << std::endl;
locker.unlock();
}
}
int main()
{
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
Future and Promise
Future和Promise是C++中的函数异步模型,一种消息传递机制,通常用于需要处理时间-consuming操作的场合。
一个Promise对象可以设置一个值,一个Future对象可以异步地获取这个值。它支持异步调用函数,让主线程可以执行异步调用,等到数据准备好再去拿取数据。
使用方法如下:
#include <future>
int factorial(std::future<int>& f)
{
int n = f.get();
int res = 1;
for(int i = n; i > 0; --i)
{
res *= i;
}
return res;
}
int main()
{
int n = 6;
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread t1(factorial, std::ref(f));
p.set_value(n);
t1.join();
std::cout << "Result: " << f.get() << std::endl;
return 0;
}
通信使用场景分析
以下是一个模拟生产者-消费者的示例,假设有一个队列,生产者往队列中添加数据,消费者从队列中获取数据。如果队列满了,则生产者线程阻塞;如果队列为空,则消费者线程阻塞。
std::mutex mu;
std::deque<int> q;
std::condition_variable cond;
const int MAX_SIZE = 3;
void producer()
{
for(int i = 0; i < 10; ++i)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [](){ return q.size() < MAX_SIZE; });
q.push_back(i);
std::cout << "Producer: Pushing value: " << i << std::endl;
locker.unlock();
cond.notify_all();
}
}
void consumer()
{
while(true)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [](){ return !q.empty(); });
int val = q.front();
q.pop_front();
std::cout << "Consumer: Gets the value: " << val << std::endl;
locker.unlock();
cond.notify_all();
}
}
int main()
{
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
结论
在多线程编程中,互斥和通信是解决线程安全问题的两个基本方法。以上是C++线程间的互斥和通信的场景分析。选择正确的互斥和通信方式,可以避免多线程编程中的常见问题,提高系统的性能和健壮性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++线程间的互斥和通信场景分析 - Python技术站