官方解釋: http://www.cplusplus.com/reference/thread/thread/joinable/
boost::thread 的一般用法
/*
thread.cpp
*/
#include <boost/thread/thread.hpp>
#include <iostream>
#include <unistd.h>
/*
* g++ thread.cpp -lboost_system -lboost_thread
*/
void helloA()
{
std::cout << "I'm thread A ! --- Start " << std::endl;
sleep(10);
std::cout << "I'm thread A ! --- OVER " << std::endl;
}
void helloB()
{
std::cout << "I'm thread B ! --- Start " << std::endl;
sleep(10);
std::cout << "I'm thread B ! --- OVER " << std::endl;
}
int main(int argc, char* argv[])
{
boost::thread thrdA(&helloA);
boost::thread thrdB(&helloB);
thrdA.join();
thrdB.join();
// join() 的作用是讓主進程等待子線程執行完畢後再繼續執行。
// 否則會不檢查子線程執行狀況,直接退出了。
return 0;
}
/*結果
I'm thread A ! --- Start
I'm thread B ! --- Start
I'm thread A ! --- OVER
I'm thread B ! --- OVER
*/
編譯方式:
g++ thread.cpp -lboost_system -lboost_thread
如果直接採用 g++ thread.cpp 會出現如下的錯誤,
/tmp/ccoutPZ3.o: In function `__static_initialization_and_destruction_0(int, int)':
thread.cpp:(.text+0xce): undefined reference to `boost::system::generic_category()'
thread.cpp:(.text+0xda): undefined reference to `boost::system::generic_category()'
thread.cpp:(.text+0xe6): undefined reference to `boost::system::system_category()'
參考這個回答:
https://stackoverflow.com/questions/13467072/c-boost-undefined-reference-to-boostsystemgeneric-category 是因爲這裏找不到鏈接庫, 所以需要 -lboost_system 和 -lboost_thread
boost::thread的幾個函數
函數 | 功能 |
---|---|
join() | 讓主進程等待子線程執行完畢後再繼續執行 |
get_id() | 獲得線程的 id 號 |
detach() | 標線程就成爲了守護線程,駐留後臺運行 |
bool joinable() | 是否爲 join() |
thread::join()是個簡單暴力的方法,主線程等待子進程期間什麼都不能做,一般情形是主線程創建thread object後做自己的工作而不是簡單停留在join上。
thread::join()還會清理子線程相關的內存空間,此後thread object將不再和這個子線程相關了,即thread object不再joinable了,所以join對於一個子線程來說只可以被調用一次,爲了實現更精細的線程等待機制,可以使用條件變量等機制。
1、可會合(joinable):這種關係下,主線程需要明確執行等待操作,在子線程結束後,主線程的等待操作執行完畢,子線程和主線程會合,這時主線程繼續執行等待操作之後的下一步操作。主線程必須會合可會合的子線程。在主線程的線程函數內部調用子線程對象的wait函數實現,即使子線程能夠在主線程之前執行完畢,進入終止態,也必須執行會合操作,否則,系統永遠不會主動銷燬線程,分配給該線程的系統資源也永遠不會釋放。
2、相分離(detached):表示子線程無需和主線程會合,也就是相分離的,這種情況下,子線程一旦進入終止狀態,這種方式常用在線程數較多的情況下,有時讓主線程逐個等待子線程結束,或者讓主線程安排每個子線程結束的等待順序,是很困難或不可能的,所以在併發子線程較多的情況下,這種方式也會經常使用。
鎖 - lock ( ) 函數
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp> //定義鎖
#include <iostream>
#include <unistd.h>
/*
* g++ thread.cpp -lboost_system -lboost_thread
*/
//boost::shared_mutex read_write_mutex;
boost::mutex lock; //使用的鎖
using namespace std;
int num = 100;
void helloA()
{
std::cout << "I'm thread A ! " << boost::this_thread::get_id() << " --- Start " << std::endl;
lock.lock(); // 鎖住變量 num, 另一處調用將在此處運行完後再繼續運行
num++;
std::cout << num <<std::endl;
sleep(3);
lock.unlock();
std::cout << "I'm thread A ! --- OVER " << std::endl;
}
void helloB()
{
std::cout << "I'm thread B ! " << boost::this_thread::get_id() << " --- Start " << std::endl;
lock.lock();
num++;
std::cout << num <<std::endl;
sleep(3);
lock.unlock();
std::cout << "I'm thread B ! --- OVER " << std::endl;
}
int main(int argc, char* argv[])
{
// 建立並執行兩個線程
boost::thread thrdA(&helloA);
boost::thread thrdB(&helloB);
thrdA.join(); // 等待子線程完成後再繼續執行主進程;
thrdB.join();
// 等待兩個 join 後纔會繼續執行
cout<< " ==== over ==== "<<endl;
return 0;
}
/*結果
I'm thread A ! 7f5792ddc700 --- Start
101
I'm thread B ! 7f57925db700 --- Start
I'm thread A ! --- OVER
102
I'm thread B ! --- OVER
==== over ====
數據 num 被鎖住, 線程B中的 num 將不能修該。 所以線程A 執行完才能修改 num 的值, 才能執行線程B。
*/
多線程函數的限制
工作的時候, 想讓發佈地圖單獨佔用一個線程, 但是發現一些問題。
boost::thread thrdA(&updateMap)
thrdA.join();
/*
if(updateMap())
{
ROS_DEBUG("Updated the map");
}
*/
return;
編譯的時候出現如下的錯誤
error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&SlamKarto::updateMap’ [-fpermissive]
boost::thread thrdA(&updateMap);
^
In file included from /usr/include/boost/thread/thread_only.hpp:22:0,
from /usr/include/boost/thread/thread.hpp:12,
from /usr/include/boost/thread.hpp:13,
from /opt/ros/indigo/include/tf/transform_listener.h:43,
from /home/moi/SLAM_Gmapping/src/slam_karto/src/slam_karto.cpp:31:
/usr/include/boost/thread/detail/thread.hpp: In instantiation of ‘void boost::detail::thread_data<F>::run() [with F = bool (SlamKarto::*)()]’:
大意錯誤就是, 多線程函數不能是非靜態成員函數, 於是我再各個函數上加了 static bool SlamKarto::updateMap( ) 但是編譯再次出錯, 還是很傻的錯誤。
error: invalid use of member ‘SlamKarto::map_mutex_’ in static member function
boost::mutex map_mutex_;
// 原函數包含太多的非靜態成員
(1)普通數據成員屬於類的一個具體的對象,只有對象被創建了,普通數據成員纔會被分配內存。而靜態數據成員屬於整個類,即使沒有任何對象創建,類的靜態數據成員變量也存在。
(2)因爲類的靜態數據成員的存在不依賴與於任何類對象的存在,類的靜態數據成員應該在代碼中被顯式地初始化,一般要在類外進行,例如上例。在C++11標準中,我們可以爲靜態成員提供const整數類型的類內初始值,不過要求靜態成員必須是字面值常量類型的constexpr(源自C++Primer中文版270頁)。
(3)外部訪問類的靜態成員能直接通過類名來訪問,例如:test::getCount()。雖然靜態成員不屬於類的某個對象,但是我們仍然可以使用類的對象、引用或指針來訪問靜態成員(源自C++Primer中文版269頁),例如:
test ac1,*ac2;
int r;
r=ac1.getCount();// 或者 r=ac2->getCount();
(4)類的靜態成員函數無法直接訪問普通數據成員(可以通過對象名間接的訪問),而類的任何成員函數都可以訪問類的靜態數據成員。
(5)靜態成員和類的普通成員一樣,也具有public、protected、private3種訪問級別,也可以具有返回值、const修飾符等參數。