赞
踩
在C++11以前,C++的多线程编程在不同到平台使用不同的API,比如linux平台使用pthread,windows平台使用winSDK中的Create,或者依赖其他第三方接口实现,一定程度上影响了代码的移植性。C++11中,引入了boost库中的多线程部分内容,形成C++标准,形成标准后的boost多线程编程部分接口基本没有变化,这样方便了以前使用boost接口开发的使用者切换使用C++标准接口,把容易把boost接口升级为C++接口。
我们通过如下几部分介绍C++11多线程方面的接口及使用方法。
#include <iostream> #include <thread>
void threadfun1() { std::cout << "I am threadfun1" << std::endl; }
void threadfun2(int iParam, std::string sParam) { std::cout << "I am threadfun2 - para:" << iParam << std::endl; }
int main() { std::thread t1(threadfun1); std::thread t2(threadfun2, 10, "hello"); std::this_thread::sleep_for(std::chrono::milliseconds(10)); t1.join(); std::cout << "t1 join" << std::endl; t2.detach(); std::cout << "t2 detach" << std::endl; system("pause"); } |
运行结果:
有以上输出结果是由于通过延时控制的,以下通道一些实例来说明std::thread工作原理。
例1:
#include <iostream> #include <thread>
void thread1() { for (int i = 0; i<10; ++i) std::cout << "I am thread1..." << std::endl; }
void thread2() { for (int i = 0; i<10; ++i) std::cout << "I am thread2..." << std::endl; }
int main(int argc, char* argv[]) { std::thread th1(thread1); // 实例化线程对象 std::thread th2(thread2); std::cout << "out:main..." << std::endl; return 0; } |
运行结果出错,证明例1代码是有问题的。因为主函数(main)在创建完thread对象之后马上结束了主线程,而此时创建出来的线程还在继续运行并还处于joinable状态,即线程还在继续存在而线程对象已经被销毁,从而导致了异常出现。
可以通道join解决以上问题:
例2:
#include <iostream> #include <thread>
void thread1() { for (int i = 0; i<10; ++i) std::cout << "thread1..." << std::endl; }
void thread2() { for (int i = 0; i<10; ++i) std::cout << "thread2..." << std::endl; }
int main(int argc, char* argv[]) { std::thread th1(thread1); // 实例化线程对象 std::thread th2(thread2); std::cout << "th1->1 status : " << th1.joinable() << std::endl; th1.join(); std::cout << "th1->2 status : " << th1.joinable() << std::endl; th2.join(); std::cout << "out : main..." << std::endl; system("pause"); return 0; } |
输出结果:
结果显示join只能运行一次,join之后对应的线程joinable状态变成false(即线程已经被join,不可再join)。同时该代码可以正常运行,但是存在一个问题,就是主线程一定要等待线程运行完成。如果让main不需要等待thread完成,可以使用detach来实现
例3:
#include <iostream> #include <thread>
void thread1() { for (int i = 0; i<10; ++i) std::cout << "thread1..." << std::endl; }
void thread2() { for (int i = 0; i<10; ++i) std::cout << "thread2..." << std::endl; }
int main(int argc, char* argv[]) { std::thread th1(thread1); // 实例化线程对象 std::thread th2(thread2); th1.detach(); th2.detach(); std::cout << "out : main..." << std::endl; system("pause"); return 0; } |
运行结果:
可以看到main在创建完thread对象之后马上结束,但创建的线程还可以继续执行。Detach的意思是把当前创建线程对象所代表的实例与宿线程对象分离,使得线程可以独立运行,在线程完成后可以自动释放线程资源。但是这种方式也存在问题,就是线程失去了控制,在主线程结束时该线程的工作可能还没完成,导致线程所做的工作可能出现问题。一下重要的线程建议不要采用这种方式。
#include <iostream> #include <thread> #include<mutex> std::mutex m; int cnt = 15;
void thread1() { m.lock(); for(; cnt>10; cnt--) std::cout << "thread1: cnt=" << cnt << std::endl; //return; // 手动制作线程异常 m.unlock(); }
void thread2() { m.lock(); cnt -= 10; std::cout << "thread2: cnt=" << cnt << std::endl; m.unlock(); }
int main(int argc, char* argv[]) { std::thread th1(thread1); std::thread th2(thread2); th1.join(); th2.join(); std::cout << "out : main..." << std::endl; system("pause"); return 0; } |
输出结果:
Mutex不是线程安全锁,如上代码在thread1中打开手动异常或者其他问题导致在解锁钱出现线程异常退出,会导致锁一直没有被释放,其他线程也就无法获取锁。
该锁是一个线程安全锁,它是基于作用域的锁,能够自解锁,当创建所对象后,可以通道lock()方法获取锁,当生命周期解锁后自动调用析构函数释放锁(unlock),因此不会出现mutex的问题。
#include <iostream> #include <thread> #include<mutex>
std::mutex m; int cnt = 15;
void thread1() { std::lock_guard<std::mutex> lock(m); for (; cnt>10; cnt--) std::cout << "thread1: cnt=" << cnt << std::endl; return; // 手动制作线程异常 }
void thread2() { std::lock_guard<std::mutex> lock(m); cnt -= 10; std::cout << "thread2: cnt=" << cnt << std::endl; }
int main(int argc, char* argv[]) { std::thread th1(thread1); std::thread th2(thread2); th1.join(); th2.join(); std::cout << "out : main..." << std::endl; system("pause"); return 0; } |
运行结果:
可以看到就算在thread1退出前手动制作异常,两个线程也可以正常运行。
1)swap()函数可以交换两个线程的句柄,如thr1.swap(th2);再用get_id发现两个线程已经交换了id
2)std::thread的拷贝构造函数是被禁用的,thread th2(th1)会不成功。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。