官方解释: http://www.cplusplus.com/reference/thread/thread/joinable/
/*
thread.cpp
*/
#include
#include
#include
/*
* 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
函数 | 功能 |
---|---|
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):表示子线程无需和主线程会合,也就是相分离的,这种情况下,子线程一旦进入终止状态,这种方式常用在线程数较多的情况下,有时让主线程逐个等待子线程结束,或者让主线程安排每个子线程结束的等待顺序,是很困难或不可能的,所以在并发子线程较多的情况下,这种方式也会经常使用。
#include
#include //定义锁
#include
#include
/*
* 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 ==== "<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::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修饰符等参数。