1. 程式人生 > >C++11 多執行緒2——Mutex的錯誤使用

C++11 多執行緒2——Mutex的錯誤使用

本系列文章主要介紹C++11中多執行緒的使用方法,主要參考書籍為《C++Concurrency IN Action》。

為了保證多執行緒訪問資料的安全性,一種通常的做法是對需要保護的資料上鎖,使用mutex保證互斥訪問。可以使用的做法是呼叫lock()unlock()函式,但是我們更加推薦使用模板類std::lock_guard,在該類的建構函式中完成lock(),而在解構函式中完成unlock()操作。這一技巧和上一章對join()函式的使用是一致的。

簡單介紹後我們來看一個可能引起mutex使用錯誤的例子。

#include <iostream>
#include <thread>
#include <mutex>
class some_data
{
public:	
	int a;
	std::string b;

	void do_someting(){ 
		a--;
		std::cout << "Break the protected." << endl; 
		std::cout << "a:" << a << endl;
	};
};
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、將受保護的資料傳遞給func函式 [8/28/2015 pan]
	}
	void printData(){
		cout << "cuttent data:" << data.a << endl;
	}
};


some_data* unprotected=NULL;
void malicious_function(some_data& protected_data)
{
	unprotected = &protected_data;
	for (int i = 0; i < 100; i++){
		unprotected->a++;
		cout << "a should in protected:" << unprotected->a << endl;
	}
}

data_wrapper x;

void wrap()
{
	while (true)
	{
		if (unprotected != NULL){
			unprotected->do_someting();<span style="white-space:pre">	</span>// 4、“未經授權”的訪問保護物件
		}
	}
}

void main()
{
	thread t(wrap);<span style="white-space:pre">			</span>// 2、開啟一個新執行緒測試
	
	x.process_data(malicious_function);		// 3、傳遞一個惡意函式 [8/28/2015 pan]
	t.join();
	x.printData();
}

程式分析:

在main()函式中我們首先開啟了一個新的執行緒去執行wrap()函式,函式在uprotected指標不為空時嘗試去訪問受保護的物件。

x.process_data()函式對保護資料上鎖,但是把data物件的引用傳遞給了不受控制的惡意函式malicious_function()。如果互斥物件mutex能正常發揮作用,執行緒t對資料的訪問會被掛起,我們應該能順利執行完100次遍歷之後再將控制權傳遞給執行緒t。執行緒t中函式do_someting()用來測試資料的保護性是否被破壞。

實際執行情況是do_someting()與malicious_function()中for迴圈交替執行,表明資料為能受到保護。