June
28th,
2018
thread
- 线程创建后调用
join
函数等待其执行结束,否则main线程先退出,导致异常。 detach
是用来和线程对象分离的,这样线程可以独立地执行。不过这样由于没有thread对象指向该线程而失去了对它的控制,当对象析构时线程会继续在后台执行,但是当主程序退出时并不能保证线程能执行完。如果没有良好的控制机制或者这种后台线程比较重要,最好不用detach而应该使用join。
class Test
{
public:
void runMultiThread();
private:
int calculate(int from, int to);
}
void Test::runMultiThread()
{
std::thread t1(&Test::calculate, this, 0, 10); // 调用类成员函数
std::thread t2(&Test::calculate, this, 11, 20);
t1.join();
t2.join();
}
mutex
用来保证线程同步的,防止不同的线程同时操作同一个共享数据。但是使用mutex是不安全的,当一个线程在解锁之前异常退出了,那么其它被阻塞的线程就无法继续下去。
int cnt = 20;
mutex m;
void t1(){
while (cnt > 0){
m.lock();
if (cnt > 0){
--cnt;
cout << cnt << endl;
}
m.unlock();
}
}
void t2(){//与t1一致}
int main()
{
thread th1(t1);
thread th2(t2);
th1.join();
th2.join();
return 0;
}
运行时cnt是依次递减的,不会因为多线程而打乱次序。
lock_guard && unique_lock
- 使用
lock_guard
和unique_lock
则相对安全,它是基于作用域的,能够自解锁,当该对象创建时,它会像m.lock()一样获得互斥锁,当生命周期结束时,它会自动析构unlock
,不会因为某个线程异常退出而影响其他线程。 lock_guard
在创建时加锁,在析构时解锁。unique_lock
可以有条件的解锁。
template <typename T>
class ThreadSafeQueue{
public:
void Insert(T value);
void Popup(T &value);
bool Empety();
private:
mutable std::mutex mut_;
std::queue<T> que_;
std::condition_variable cond_;
};
template <typename T>
void ThreadSafeQueue::Insert(T value){
std::lock_guard<std::mutex> lk(mut_);
que_.push_back(value);
cond_.notify_one(); // 唤醒其他wait函数
}
template <typename T>
void ThreadSafeQueue::Popup(T &value){
std::unique_lock<std::mutex> lk(mut_);
cond_.wait(lk, [this]{return !que_.empty();});
value = que_.front();
que_.pop();
}
条件变量
条件变量是一种同步原语(Synchronization Primitive)用于多线程之间的通信,它可以阻塞一个或同时阻塞多个线程 成员函数
- notify_one notify_all:类似于发出脉冲信号,如果对wait的调用发生在notify之后是不会被唤醒的
- wait wait_for wait_until