結合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();
}
這題目有歧義,我就沒有給出解決方案了。