1. Race conditions 对资源竞争问题的处理
最常用的就是锁机制 mutexes
#include <iostream>
#include <thread>
#include <functional>
#include <chrono>
#include <mutex>
#include <algorithm>
#include <list>
std::list<int> some_list;
std::mutex some_mutex;
void add_to_list(int new_value)
{
std::lock_guard<std::mutex> guard(some_mutex);
some_list.push_back(new_value);
}
bool 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();
}
void func1()
{
for(int i=0; i<10; i++)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "thread1, func1" << std::endl;
add_to_list(i);
}
std::cout << "list_contains(8): " << list_contains(8) << std::endl;
}
void func2()
{
for(int i=10; i<20; i++)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "thread2, func2" << std::endl;
add_to_list(i);
}
std::cout << "list_contains(15): " << list_contains(15) << std::endl;
}
int main()
{
std::thread t1(func1);
std::thread t2(func2);
t1.join();
t2.join();
return 0;
}
更合理的方式是应该将list, mutex 以及操作他们的函数封装在类中。
2. 使用mutex锁住共享资源时需要注意
Any code that has access to that pointer or reference can now access (and potentially modify) the protected data without locking the mutex. 如果通过指针和引用将被保护的数据传递出来,之后不进行lock也是可以访问的,这时很危险的。
class some_data
{
private:
int a;
std::string b;
public:
void do_something();
};
class data_wrapper
{
private:
some_data m_data;
std::mutex m;
public:
template<typename Function>
void process_data(Function func)
{
std::lock_guard<std::mutex> l(m);
func(data); //这里通过some_data&引用将data传出去了,
//从而外部可以避开锁来修改本来想要lock的数据
}
};
some_data* unprotected;
void malicious_function(some_data& protected_data)
{
unprotected = &protected_data;
}
data_wrapper x;
void foo()
{
x.process_data(malicious_function());
unprotected->do_something(); //避开了lock,也可以修改数据
}