在編程中,引入了對象互斥鎖的概念,來保證共享數據操做的完整性。每一個對象都對應於一個可稱爲" 互斥鎖" 的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。ios
#include <iostream>#include <boost/thread.hpp>using namespace std;int g_num = 0;
boost::mutex mu; //定義互斥鎖對象
int Func(int nCount){for (int i = 0; i < nCount; i++){boost::mutex::scoped_lock lock(mu); //對共享數據進行操做,需加鎖
g_num++;cout << __FUNCTION__ << ": " << g_num << endl;
}return g_num;
}int _tmain(int argc, _TCHAR* argv[]){boost::thread th1(Func, 100);boost::thread th2(Func, 200);th1.join();th2.join();return 0;
}
boost::shared_mutex rw_mu; //定義讀寫鎖
int Write(int nCount){for (int i = 0; i < nCount; i++){boost::unique_lock<boost::shared_mutex> lock(rw_mu); //加惟一鎖
g_num++;cout << __FUNCTION__ << ": " << g_num << endl;
}return g_num;
}void Read(int nCount){for (int i = 0; i < nCount; i++){boost::shared_lock<boost::shared_mutex> lock(rw_mu); //加共享鎖
cout << __FUNCTION__ << ": " << g_num << endl;
}}int _tmain(int argc, _TCHAR* argv[]){boost::thread th1(Write, 100);boost::thread th2(Read, 100);boost::thread th3(Read, 100);th1.join();th2.join();th3.join();return 0;
}
條件量相對於互斥鎖和讀寫鎖來講,並非那麼好理解,簡單點說,條件變量就是用於等待某個條件被觸發,但爲何要配合鎖使用呢,由於咱們的等待不能是乾等,那樣可能會出現死鎖。編程
如線程A負責添加任務到隊列,線程B負責處理隊列中的任務,隊列就是兩個線程的共享資源,使用前必須加鎖,但若是B線程加鎖後,發現隊列中沒有數據,而後等待,A線程準備添加任務時,發現多線程
鎖已經被佔用,因而就無法添加任務,就造成了死鎖。但若是我等待時,釋放鎖資源,A線程就能正常添加任務,完成後通知B線程能夠處理了,那麼整個流程就暢通無阻了,這就是條件量的做用。函數
#include <queue>boost::mutex g_ioMutex; //輸出控制鎖
template<typename T>class CMsgQueue
{public:
CMsgQueue(size_t n):m_nCapacity(n){}void Push(const T& val){{boost::mutex::scoped_lock lock(m_mu); //加鎖
while(m_val.size() == m_nCapacity) //隊列已滿{{boost::mutex::scoped_lock lock(g_ioMutex);cout << "隊列已滿" << endl;
}m_condPush.wait(m_mu); //等待,將暫時的解鎖
}m_val.push(val); //添加數據到隊列
}m_condPop.notify_one(); //通知讀線程
}void Pop(T& val)
{{boost::mutex::scoped_lock lock(m_mu); //加鎖
while(m_val.size() == 0) //隊列爲空{{boost::mutex::scoped_lock lock(g_ioMutex);cout << "隊列爲空" << endl;
}m_condPop.wait(m_mu); //等待可讀,
}val = m_val.front(); //讀取數據
m_val.pop();}m_condPush.notify_one(); //通知寫線程
}private:
queue<T> m_val; //隊列
int m_nCapacity; //隊列最大容量boost::condition_variable_any m_condPush; //寫入條件量
boost::condition_variable_any m_condPop; //讀取條件量
boost::mutex m_mu; //互斥鎖
};CMsgQueue<int> g_numQueue(10);
void FuncA(int nCount){for (int i = 0; i < nCount; i++){{boost::mutex::scoped_lock lock(g_ioMutex);cout << __FUNCTION__ << " Put " << i << endl;
}g_numQueue.Push(i);}}void FuncB(int nCount){for (int i = 0; i < nCount; i++){int val;
g_numQueue.Pop(val);boost::mutex::scoped_lock lock(g_ioMutex);cout << __FUNCTION__ << " Get " << val << endl;
}}int _tmain(int argc, _TCHAR* argv[]){boost::thread th1(FuncA, 50);boost::thread th2(FuncB, 20);boost::thread th3(FuncB, 30);th1.join();th2.join();th3.join();return 0;
}
在多線程程序中,鎖的使用須要特別的當心,好比,咱們將FuncA稍微改一下:spa
void FuncA(int nCount){for (int i = 0; i < nCount; i++){boost::mutex::scoped_lock lock(g_ioMutex);cout << __FUNCTION__ << " Put " << i << endl;
g_numQueue.Push(i);}}
若是改爲這樣,程序將陷入死鎖,咱們輕輕鬆鬆就製造了一個死鎖案例。線程
A線程佔用了輸入鎖,那麼B線程的Pop函數將一直在獲取輸入鎖的地方等待,但它已經佔用了m_mu鎖,A線程也就只能一直在等待m_mu,故造成了死鎖。code