Boost(六)——多執行緒
結合Boost官網
多執行緒的難點在於同步執行,需要“鎖”控制所有權。
鎖有分:互斥鎖,條件變數...
互斥鎖:boost::mutex 獲取和釋放成對存在,也可以用boost::lock_guard<boost::mutex> lock(mutex);
boost::lock_guard在其內部構造和解構函式分別自動呼叫 lock()
和 unlock()
類似於智慧指標。
boost::try_lock():嘗試獲取互斥體
lock.owns_lock():判斷是否獲取到互斥體
lock.timed_lock():等待一定的時間以獲得互斥體
獨佔鎖:boost::unique_lock
非獨佔鎖:boost::shared_lock
一般的,資源在操作(增、刪等)的時候,為了防止其他執行緒“干擾”,採用獨佔鎖將其他執行緒拒之門外。
而對資源讀取的時候、可以多個執行緒同時進行,用非獨佔鎖即可。
注意的是:獨佔鎖需要手動解鎖,否則等該執行緒結束後,其他執行緒才能訪問該資源。切記!!!
在實際運用中、不會像事例展示的、用wait(1)//等待1s後再操作,畢竟計算機世界裡的1s真的太長了。。。
絕大多數情況下,採用阻塞模式。
舉個栗子,一個人等著水燒開(阻塞取水執行緒),燒水壺鳴笛(喚醒取水執行緒),人再把水取走(執行取水執行緒)。
引入條件變數:boost::conditon_variable_any
cond.wait(mutex);//等待喚醒,在阻塞喚醒之後,mutex又自動鎖上
cond.notify_all();//喚醒所有阻塞
初始化函式問題:
若多個執行緒呼叫初始化函式,都要進行初始化,相比以前用靜態變數控制訪問唯一性的方法就存在程序中只能進行一次初始化。
為了解決這個問題,引入TLS(Thread Local Save)執行緒本地儲存變數:static boost::thread_specific_ptr<bool>
reset()函式將bool型變數地址儲存到TLS中,意味著這是該執行緒專屬的變數,其他執行緒訪問不了。
練習題:
1、重構下面的程式用兩個執行緒來計算總和。由於現在許多處理器有兩個核心,應利用執行緒減少執行時間。
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/cstdint.hpp>
#include <iostream>
int main()
{
boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
boost::uint64_t sum = 0;
for (int i = 0; i < 1000000000; ++i)
sum += i;
boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time();
std::cout << end - start << std::endl;
std::cout << sum << std::endl;
}
解答:
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/cstdint.hpp>
#include <boost\thread.hpp>
#include <iostream>
using namespace std;
boost::uint64_t g_tmp;
boost::uint64_t m_sum1;
boost::uint64_t m_sum2;
void sum1()
{
for (int i = 0; i < g_tmp; i++)
{
m_sum1 += i;
}
}
void sum2()
{
for (int i = g_tmp; i < 1000000000; i++)
{
m_sum2 += i;
}
}
int main()
{
m_sum1 = m_sum2 = 0;
g_tmp = 1000000000 / 2;
boost::thread t1(sum1);
boost::thread t2(sum2);
t1.join();
t2.join();
cout << "sum >> " << m_sum1 + m_sum2 << endl;
system("pause");
}
2、通過利用處理器儘可能同時執行多的執行緒,把例1一般化。 例如,如果處理器有四個核心,就應該利用四個執行緒。
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/cstdint.hpp>
#include <boost\thread.hpp>
#include <iostream>
#include <utility>
#define Max_Thread 4
using namespace std;
boost::uint64_t m_sum;
boost::shared_mutex mutex;
#define max 10000000
void sum(int start, int end)
{
for (uint64_t i = start; i < end; i++)
{
boost::unique_lock<boost::shared_mutex> lock(mutex);
m_sum += i;
}
}
int main()
{
m_sum = 0;
boost::thread t[Max_Thread];
for (int i = 0; i < Max_Thread; i++)
{
t[i] = boost::thread(sum, max / Max_Thread * i, max / Max_Thread * (i + 1) );
}
boost::posix_time::ptime start1 = boost::posix_time::microsec_clock::local_time();
for (int i = 0; i < Max_Thread; i++)
{
t[i].join();
}
boost::posix_time::ptime end1 = boost::posix_time::microsec_clock::local_time();
cout << "sum >> " << m_sum << endl;
std::cout << end1 - start1 << std::endl;
boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
boost::uint64_t sum = 0;
for (int i = 0; i < max; ++i)
sum += i;
boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time();
std::cout << end - start << std::endl;
std::cout << sum << std::endl;
system("pause");
}
其實一般不會這麼用,如果數量級達到百萬以上的時候,對於鎖需要重複開鎖和關鎖,耗費的時間是恐怖的。
3、修改下面的程式,在 main()
中自己的執行緒中執行 thread()
。 程式應該能夠計算總和,然後把結果輸入到標準輸出兩次。 但可以更改 calculate()
,print()
和 thread()
的實現,每個函式的介面仍需保持一致。 也就是說每個函式應該仍然沒有任何引數,也不需要返回一個值。
#include <iostream>
int sum = 0;
void calculate()
{
for (int i = 0; i < 1000; ++i)
sum += i;
}
void print()
{
std::cout << sum << std::endl;
}
void thread()
{
calculate();
print();
}
int main()
{
thread();
}
這題目有歧義,我就沒有給出解決方案了。