c++学习笔记(四)- 多线程 互斥 cmake
std::mutex 的成员函数
- 构造函数,std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。
- lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:(1). 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。(2). 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
- unlock(), 解锁,释放对互斥量的所有权。
- try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况,(1). 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
用到了c++11规范里的多线程,然后编译的时候就报错了,中午各种改CMakeLists没搞定,下午师弟介绍文档,cmake practice,参考第七章,搞定了。
只需要CMakeLists.txt里添加一句话:
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++11 -pthread")
开始的时候没有-pthread能make,但运行的时候就崩溃了,参考这里解决。
根据讨论,桌面Linux环境这样就行了,如果是嵌入式交叉编译环境的话,还需要显示添加
find_package (Threads)
万一以后要写树莓派呢~
存疑:
中午试的不成功的CMakeLists是从已经编译通过的ORB_SLAM2里拿过来的,如下,当时编译没有问题,且运行tum_mono,cpu使用率从低于100%到最后能高于200%,应该3个线程都开了才会占用这么多吧,不太清楚为什么拿到自己的工程里不行。
1 # Check C++11 or C++0x support 2 include(CheckCXXCompilerFlag) 3 CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 4 CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) 5 if(COMPILER_SUPPORTS_CXX11) 6 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 7 elseif(COMPILER_SUPPORTS_CXX0X) 8 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") 9 else() 10 message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 11 endif()
2017.12.15
今天被问到static修饰的局部变量如果在并行时会怎样,当时有点懵,知道并行的时候是要加互斥锁的,不过如果不加会怎样呢,没有写过并行啊,会乱吧,回来拿多线程试了一下,还是mutex那段代码:
void print_block(int n, char c) { mtx.lock(); static int i = 0; for (i = 0; i<n; ++i) { std::cout << c<<i; } std::cout << '\n'; mtx.unlock(); }
如果加了互斥锁,不管是不是静态输出都长这样:
不加互斥锁,静态局部变量 static int i 输出:
非静态局部变量 int i 输出:
个人理解:
用static修饰的局部变量在编译时初始化好,存储在全局区域,不过多少个线程,都去访问这个局部变量;
而没有用static修饰的局部变量在函数调用的时候才分配空间,放在堆栈,这里用多线程,那么每个线程建立的时候给它分配一次内存,并且是从线程自己的堆栈空间里分配出来的。
晚饭后继续试,下面这段代码:
int staticTest(int n) { static int idx = 0; idx = n-1;
cout << idx; if(idx) staticTest(idx ); return 1; } int _tmain(int argc, _TCHAR* argv[]) { std::thread th1(staticTest, 5); std::thread th2(staticTest, 8); th1.join(); th2.join(); cout << "hello world" << endl; return 0; }
输出长这样:
去掉static以后:
静态加上互斥:
mtx.lock(); cout << idx; mtx.unlock();
这里 c/c++中的static关键字详解 用法1 解释了上述现象:
用法1:函数内部声明的static变量,可作为对象间的一种通信机制
如果一局部变量被声明为static,那么将只有唯一的一个静态分配的对象,它被用于在该函数的所有调用中表示这个变量。这个对象将只在执行线程第一次到达它的定义使初始化。
仍旧觉得有点乱,暂且保留敬畏心,static要慎用(依稀记得小时候编单片机很常用,可以用很巧妙的方式做定时器计数,不过单片机不用多线程啊)