C++11新加入的std::thread是由boost::thread发展而来,二者用法极其相似,基本上就是改一下头文件和名称空间的问题,例外是thread_group,thread_group,它们都是boost的组件,但并不是标准库的组件,所以需要自己实现一下。还有boost中的thread_group使用shared_mutex来进行线程同步,shared_mutex也没有进入标准库,所以需要用什么东西来替代一下。shared_mutex没能进入标准库的原因就是C++标准化委员会认为目前可行的shared_mutex实现方案在性能上并不合算,不如直接使用mutex,既然如此,就直接用mutex吧,相应的shared_lock也修改成lock_guard即可。
本文就用boost::thread为例来简要说下C++的线程库,然后和Rust的线程库进行简要对比:
一.创建线程:
//编译: g++ -Wall thread01.cpp -lboost_thread -o thread01 -lboost_system
//执行:./thread01
#include <boost/thread/thread.hpp>
#include <iostream>
using namespace boost;
void test()
{
std::cout<<"hello world!"<<std::endl;
}
int main(int argc, char const *argv[]) {
boost::thread t1(&test);
t1.join();
return 0;
}
使用std::thread库的代码几乎和上面一模一样:
//编译:g++ -std=c++11 thread001.cpp -lpthread -o thread001
//执行:./thread001
#include <thread>
#include <iostream>
using namespace std;
void test()
{
std::cout<<"hello world!"<<std::endl;
}
int main(int argc, char const *argv[]) {
std::thread t1(&test);
t1.join();
return 0;
}
上面代码中的thread()会构造一个表示当前执行线程的线程对象t1,这个thread对象把test作为它的起始函数。新建了一个新线程t1之后,程序就有两个线程:主线程和t1线程:主线程起始于main()函数而t1线程起始于test()函数。
如果t1启动之后,主线程什么也不管往下执行,它就会一口气运行到main()结束,从而结束整个程序。所以我们需要调用一个join()函数来等待这个新线程的执行过程。join()是个简单暴力的方法:新线程调用join()之后,主线程会一直等待新进程,直到新线程执行完毕(Waits for this thread to die)。
Rust 的标准库为线程提供了一个库,它允许你以并行的方式运行 Rust 代码。这里是使用 std::Thread 的一个简单例子:
//thread01.rs
//编译:rustc thread01.rs
//执行:./thread01
use std::thread;
fn main() {
let t = thread::spawn(move || {
"Hello from a thread!"
});
println!("{}", t.join().unwrap());
}
Rust创建线程的方法可以总结为:
use std::thread;
thread::spawn(move || {
// 这里是新建线程的执行逻辑
});
thread:spawn() 方法接受一个封闭参数,这个参数会在一个新线程中执行。它返回该线程的句柄,它可以用来在等待子线程完成之后提取其结果。
默认情况下,新创建的子线程与原先的父线程是分离的关系。也就是说,子线程可以在父线程结束后继续存在,除非父线程是主线程。因为我们知道,如果一个进程的主线程也退出了,这个进程就会终止,其它所有线程都会随之结束。
如果我们需要等待子线程执行结束,那么可以使用join方法:
//thread02.rs
//编译:rustc thread02.rs
//执行:./thread02
use std::thread;
// child 的类型是 JoinHandle<T>,这个T是什么呢,当然是闭包的返回类型了
fn main() {
let child = thread::spawn(move || {
"hello world"
});
let res = child.join();// 父线程等待子线程结束
println!("{}", res.unwrap());
}