案例:
#include<iostream> #include<string> #include<thread>
using namespace std;
void function_1() { for (int i = 0; i > -100; i--) { std::cout << "From t1:" << i << std::endl;
} } int main() { thread t1(function_1); for (int i = 0; i < 100; i++) { cout << "From main:" << i << endl; } t1.join(); } |
输出
可以看到其中有Fromt1:From main:50
原因在于代码中的cout为两个线程共同竞争使用。解决的方法使用互斥对象来同步资源访问。
#include<iostream> #include<string> #include<thread> #include<mutex>
using namespace std;
std::mutex mu;
void shared_Print(string msg,int id) {
mu.lock(); std::cout << msg << id << endl; mu.unlock();
} void function_1() { for (int i = 0; i > -100; i--) { //std::cout << "From t1:" << i << std::endl; //using shared_Print function instead of function_1 shared_Print("From t1", i);
} } int main() { thread t1(function_1); for (int i = 0; i < 100; i++) { //cout << "From main:" << i << endl; shared_Print("From Main()", i); } t1.join(); } |
但是,这样使用下,有一种情况发生时将会造成死锁的发生。
在程序mu.lock与mu.unlock之间的函数如果抛出意外,此事程序将不能解锁,从而使得程序锁住。
使用另外一种方式来替代:
Std::lock_guard<std::mutex>guard(mu)
#include<iostream> #include<string> #include<thread> #include<mutex>
using namespace std;
std::mutex mu;
void shared_Print(string msg,int id) {
std::lock_guard<std::mutex> guard(mu); std::cout << msg << id << endl;
} void function_1() { for (int i = 0; i > -100; i--) { //std::cout << "From t1:" << i << std::endl; //using shared_Print function instead of function_1 shared_Print("From t1", i);
} } int main() { thread t1(function_1); for (int i = 0; i < 100; i++) { //cout << "From main:" << i << endl; shared_Print("From Main()", i); } t1.join(); } |
#end
另外一个问题来了,cout是全局型的,因此其他程序段可以继续使用cout,从而没有实现完全意义上的线程保护,。即没有在互斥量mu中作为私有函数供(绑定)使用。
使用类可以解决该问题。
#include<iostream> #include<string> #include<thread> #include<mutex> #include<fstream> //将数据保存到文件中使用fsteam头文件
using namespace std;
std::mutex mu; class lofFile { public: lofFile() // { f.open("log.txt"); } void share_Print(std::string id, int value) //成员函数 { std::lock_guard<mutex> locker(m_mutex); f << "from " << id << value << endl; } protected: private: mutex m_mutex; ofstream f; };
void function_1(lofFile& l) //添加引用 { for (int i = 0; i > -100; i--) { //std::cout << "From t1:" << i << std::endl; //using shared_Print function instead of function_1 l.share_Print("From t1", i);
} } int main() { lofFile l; thread t1(function_1, std::ref(l)); //一定注意添加引用 for (int i = 0; i < 100; i++) { //cout << "From main:" << i << endl; l.share_Print("From Main()", i); } t1.join(); } |
找到文件夹下的文件
清单3.2 无意中传递了保护数据的引用
class some_data { int a; std::string b; public: void do_something(); }; class data_wrapper { private: some_data data; std::mutex m; public: template<typename Function> void process_data(Function func) { std::lock_guard<std::mutex> l(m); func(data); // 1 传递"保护"数据给用户函数 } }; some_data* unprotected; void malicious_function(some_data& protected_data) { unprotected=&protected_data; } data_wrapper x; void foo() { x.process_data(malicious_function); // 2 传递一个恶意函数 unprotected->do_something(); // 3 在无保护的情况下访问保护数据 } |
例子中process_data看起来没有任何问题, std::lock_guard 对数据做了很好的保护,但调用用户提供的函数func①,就意味着foo能够绕过保护机制将函数 malicious_function 传递进去②,在没有锁定互斥量的情况下调用do_something()