boost::thread簡要分析(1):thread
阿新 • • 發佈:2019-01-03
昨天在寫作“大衛的Design Patterns學習筆記”過程中,編寫了一個多執行緒Producer-Consumer的示例,其中用到了boost::thread,但線上程同步的問題上遇到了些問題,到csdn和vckbase上發帖子問了一下,也沒人回答,沒有辦法,只好晚上回家搬出原始碼研究了一下,總算解決了問題,下面將自己的理解寫下來,與大家分享、討論。
注:以下討論基於boost1.32.0。
boost::thread庫跟boost::function等很多其它boost組成庫不同,它只是一個跨平臺封裝庫(簡單的說,就是根據不同的巨集呼叫不同的API),裡面沒有太多的GP程式設計技巧,因此,研究起來比較簡單。
boost::thread庫主要由以下部分組成:
thread
mutex
scoped_lock
condition
xtime
barrier
下面依次解析如下:
thread
thread自然是boost:: thread庫的主角,但thread類的實現總體上是比較簡單的,前面已經說過,thread只是一個跨平臺的執行緒封裝庫,其中按照所使用的編譯選項的不同,分別決定使用Windows執行緒API還是pthread,或者Macintosh Carbon平臺的thread實現。以下只討論Windows,即使用BOOST_HAS_WINTHREADS的情況。
thread類提供了兩種建構函式:
thread::thread()
thread::thread(const function0<void>& threadfunc)
第一種建構函式用於呼叫GetCurrentThread構造一個當前執行緒的thread物件,第二種則通過傳入一個函式或者一個functor來建立一個新的執行緒。第二種情況下,thread類在其建構函式中間接呼叫CreateThread來建立執行緒,並將執行緒控制代碼儲存到成員變數m_thread中,並執行傳入的函式,或執行functor的operator ()方法來啟動工作執行緒。
此外,thread類有一個Windows下的程式設計師可能不大熟悉的成員函式join,執行緒(通常是主執行緒)可以通過呼叫join函式來等待另一執行緒(通常是工作執行緒)退出,join的實現也十分簡單,是呼叫WaitForSingleObject來實現的:
WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
我們可以用以下三種方式啟動一個新執行緒:
1、傳遞一個工作函式來構造一個工作執行緒
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
boost::mutex io_mutex;
void count() // worker function
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << i << std::endl;
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(&count);
boost::thread thrd2(&count);
thrd1.join();
thrd2.join();
return 0;
}
2、傳遞一個functor物件來構造一個工作執行緒
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
boost::mutex io_mutex;
struct count
{
count(int id) : id(id) { }
void operator()()
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock lock(io_mutex); // lock io, will be explained soon.
std::cout << id << ": " << i << std::endl;
}
}
int id;
};
int main(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}
3、無需將類設計成一個functor,藉助bind來構造functor物件以建立工作執行緒
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex io_mutex;
struct count
{
static int num;
int id;
count() : id(num++) {}
int do_count(int n)
{
for (int i = 0; i < n; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << id << ": " << i << std::endl;
}
return id;
}
};
int count::num = 1;
int main(int argc, char* argv[])
{
count c1;
boost::thread thrd1(boost::bind(&count::do_count, &c1, 10));
thrd1.join();
return 0;
}
其中bind是一個函式模板,它可以根據後面的例項化引數構造出一個functor來,上面的boost::bind(&count::do_count, &c1, 10)其實等價於返回了一個functor:
struct countFunctor
{
int operator() ()
{
(&c1)->do_count(10); // just a hint, not actual code
}
};
因此,以後就跟2中是一樣的了。
注:以下討論基於boost1.32.0。
boost::thread庫跟boost::function等很多其它boost組成庫不同,它只是一個跨平臺封裝庫(簡單的說,就是根據不同的巨集呼叫不同的API),裡面沒有太多的GP程式設計技巧,因此,研究起來比較簡單。
boost::thread庫主要由以下部分組成:
thread
mutex
scoped_lock
condition
xtime
barrier
下面依次解析如下:
thread
thread自然是boost::
thread類提供了兩種建構函式:
thread::thread()
thread::thread(const function0<void>& threadfunc)
第一種建構函式用於呼叫GetCurrentThread構造一個當前執行緒的thread物件,第二種則通過傳入一個函式或者一個functor來建立一個新的執行緒。第二種情況下,thread類在其建構函式中間接呼叫CreateThread來建立執行緒,並將執行緒控制代碼儲存到成員變數m_thread中,並執行傳入的函式,或執行functor的operator
此外,thread類有一個Windows下的程式設計師可能不大熟悉的成員函式join,執行緒(通常是主執行緒)可以通過呼叫join函式來等待另一執行緒(通常是工作執行緒)退出,join的實現也十分簡單,是呼叫WaitForSingleObject來實現的:
WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
我們可以用以下三種方式啟動一個新執行緒:
1、傳遞一個工作函式來構造一個工作執行緒
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
boost::mutex io_mutex;
void count() // worker function
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << i << std::endl;
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(&count);
boost::thread thrd2(&count);
thrd1.join();
thrd2.join();
return 0;
}
2、傳遞一個functor物件來構造一個工作執行緒
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
boost::mutex io_mutex;
struct count
{
count(int id) : id(id) { }
void operator()()
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock lock(io_mutex); // lock io, will be explained soon.
std::cout << id << ": " << i << std::endl;
}
}
int id;
};
int main(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}
3、無需將類設計成一個functor,藉助bind來構造functor物件以建立工作執行緒
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex io_mutex;
struct count
{
static int num;
int id;
count() : id(num++) {}
int do_count(int n)
{
for (int i = 0; i < n; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << id << ": " << i << std::endl;
}
return id;
}
};
int count::num = 1;
int main(int argc, char* argv[])
{
count c1;
boost::thread thrd1(boost::bind(&count::do_count, &c1, 10));
thrd1.join();
return 0;
}
其中bind是一個函式模板,它可以根據後面的例項化引數構造出一個functor來,上面的boost::bind(&count::do_count, &c1, 10)其實等價於返回了一個functor:
struct countFunctor
{
int operator() ()
{
(&c1)->do_count(10); // just a hint, not actual code
}
};
因此,以後就跟2中是一樣的了。