线程之间共享资源对于线程的安全性很重要,不正确的共享资源会导致多线程程序产生许多不可意料的bug
CP3
1. 线程之间共享数据的问题
读取数据的情况不会发生问题。如果多个线程同时需要对数据进行修改不制定相应的规则会发生奇怪的后果。书中举例了双向链表的读写删除操作时候多线程可能引发的问题。最基本的std::list 就是一个双向链表
1)并发冲突,资源竞争(Race condition)
benign race condition(良性的资源竞争) 不用太care
problematic race condition (有问题的资源竞争)重点 通常发生于一个操作需要分多次修改数据,而当操作只完成某一步时别的线程需要对数据进行访问。这就会产生不良的后果
2)避免有问题的资源竞争(problematic race condition)
a.对数据进行适当的保护 (mutex 互斥量)
b.修改数据结构 lock-free 编程
c.使用类似数据库的transaction机制
软件事务内存(software transactional memory STM)
2. 使用mutex保护共享数据
在访问共享资源之前先lock mutex,访问结束以后unlock mutex。在这个过程中所有尝试lock mutex的线程会等待mutex被unlock以后才执行对他的lock
1)在C++中使用mutex
#include <iostream>
#include <thread>
#include <tr1/memory>
#include <list>
#include <mutex>
#include <algorithm>class mutex_sample
{
public:
void add_to_list(int new_value);
bool list_contains(int value_to_find);
private:
std::list<int> some_list;
std::mutex some_mutex;
};void mutex_sample::add_to_list(int new_value)
{
std::lock_guard<std::mutex> guard(some_mutex);
some_list.push_back(new_value);
std::cout<<new_value<<std::endl;
}bool mutex_sample::list_contains(int value_to_find)
{
std::lock_guard<std::mutex> guard(some_mutex);
return std::find(some_list.begin(), some_list.end(), value_to_find)!=some_list.end();
}int main()
{
mutex_sample mtx;
std::vector<std::thread> threads;
for(int i=0; i<5; ++i) {
threads.push_back(std::thread([=,&mtx]{
mtx.add_to_list(i);
}));
}
std::for_each(threads.begin(), threads.end(),std::mem_fn(&std::thread::join)); if(mtx.list_contains(3))
std::cout<<"Find the value"<<std::endl;
//do something else.
return 0;
}一个简单的基于面向对象的使用mutex保护共享资源的例子,但是该例子有隐患。任何试图将保护资源通过引用或者指针放回给外界都会绕开mutex的保护从而造成资源竞争。