ThreadNote
C++11 之前
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
参数
说明
thread
子例程返回的新线程的不透明的唯一标识符。
attr
一个opaque属性对象,可用于设置线程属性。您可以指定线程属性对象,或者为默认值指定NULL。
start_routine
线程创建后将执行的C ++例程。
arg
可以传递给start_routine的单个参数。它必须通过引用传递为void类型的指针转换。如果不传递参数,则可以使用NULL。
C++11
#include <thread>
std::thread nth(&ctr::Class::func, this); // 创建运行对象成员函数的线程
std::thread nth(func, "HELLO");
构造函数
构造函数
说明
备注
thread() noexcept;
默认构造函数
创建空的std::thread执行对象
template explicit thread (Fn&& fn, Args&&... args);
初始化
创建std::thread对象,该对象可被joinable,信产生的线程会调用fn函数,该函数的参数由args给出
thread (const thread&) = delete;
拷贝构造(被禁用 - delete)
意味着std::thread对象不可被拷贝
thread (thread&& x) noexcept;
移动构造
调用成功之后x不代表任何std::thread执行对象
Example
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
void f1(int n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread " << n << " executing\n";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void f2(int& n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 2 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
int main()
{
int n = 0;
std::thread t1; // t1 is not a thread
std::thread t2(f1, n + 1); // pass by value
std::thread t3(f2, std::ref(n)); // pass by reference
std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
t2.join();
t4.join();
std::cout << "Final value of n is " << n << '\n';
}
#include <iostream>
#include <unistd.h>
#include <thread>
#include <unistd.h>
using namespace std;
class A {
public:
void f(string str) {
cout << "A::f() " << str << endl;
sleep(3);
}
void fn() {
cout << "A::fn()" << endl;
sleep(3);
}
};
void f(string str) {
cout << "f(string str)" << str << endl;
sleep(3);
}
void fn() {
cout << "fn()" << endl;
sleep(3);
}
int main() {
A a;
std::thread nth(f, "Hello"); // 有参数的方法
sleep(1);
std::thread nfth(fn); // 无参方法
sleep(1);
std::thread nfthc(&A::f, &a, "hello"); // 有参类方法
while (true) {}
return 0;
}
/** Output
f(string str)Hello
fn()
A::f() hello
*/
// constructing threads
#include <iostream> // std::cout
#include <atomic> // std::atomic
#include <thread> // std::thread
#include <vector> // std::vector
std::atomic<int> global_counter (0);
void increase_global (int n) { for (int i=0; i<n; ++i) ++global_counter; }
void increase_reference (std::atomic<int>& variable, int n) { for (int i=0; i<n; ++i) ++variable; }
struct C : std::atomic<int> {
C() : std::atomic<int>(0) {}
void increase_member (int n) { for (int i=0; i<n; ++i) fetch_add(1); }
};
int main ()
{
std::vector<std::thread> threads;
std::cout << "increase global counter with 10 threads...\n";
for (int i=1; i<=10; ++i)
threads.push_back(std::thread(increase_global,1000));
std::cout << "increase counter (foo) with 10 threads using reference...\n";
std::atomic<int> foo(0);
for (int i=1; i<=10; ++i)
threads.push_back(std::thread(increase_reference,std::ref(foo),1000));
std::cout << "increase counter (bar) with 10 threads using member...\n";
C bar;
for (int i=1; i<=10; ++i)
threads.push_back(std::thread(&C::increase_member,std::ref(bar),1000));
std::cout << "synchronizing all threads...\n";
for (auto& th : threads) th.join();
std::cout << "global_counter: " << global_counter << '\n';
std::cout << "foo: " << foo << '\n';
std::cout << "bar: " << bar << '\n';
return 0;
}
赋值操作
赋值
说明
备注
thread& operator=(thread&& rhs) noexcept;
Move 赋值操作
如果当前对象不可 joinable
,需要传递一个右值引用(rhs
)给 move
赋值操作;如果当前对象可被 joinable
,则会调用 terminate
() 报错。
thread& operator=(const thread&) = delete;
拷贝赋值操作 [deleted]
被禁用,因此 std::thread
对象不可拷贝赋值。
#include <stdio.h>
#include <stdlib.h>
#include <chrono> // std::chrono::seconds
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for
void thread_task(int n) {
std::this_thread::sleep_for(std::chrono::seconds(n));
std::cout << "hello thread "
<< std::this_thread::get_id()
<< " paused " << n << " seconds" << std::endl;
}
int main(int argc, const char *argv[])
{
std::thread threads[5];
std::cout << "Spawning 5 threads...\n";
for (int i = 0; i < 5; i++) {
threads[i] = std::thread(thread_task, i + 1);
}
std::cout << "Done spawning threads! Now wait for them to join\n";
for (auto& t: threads) {
t.join();
}
std::cout << "All threads joined.\n";
return EXIT_SUCCESS;
}
其他成员函数
get_id()
:获取线程IDjoinable()
:检查线程是否可被join检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的
如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的
detach
:将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放。swap
:交换两个线程对象所代表的底层句柄(underlying handles)native_handle
:返回 native handle#include <thread> #include <iostream> #include <chrono> #include <cstring> #include <pthread.h> std::mutex iomutex; void f(int num) { std::this_thread::sleep_for(std::chrono::seconds(1)); sched_param sch; int policy; pthread_getschedparam(pthread_self(), &policy, &sch); std::lock_guard<std::mutex> lk(iomutex); std::cout << "Thread " << num << " is executing at priority " << sch.sched_priority << '\n'; } int main() { std::thread t1(f, 1), t2(f, 2); sched_param sch; int policy; pthread_getschedparam(t1.native_handle(), &policy, &sch); sch.sched_priority = 20; if(pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) { std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n'; } t1.join(); t2.join(); }
终止线程
#include <iostream>
#include <thread>
#include <pthread.h>
using namespace std;
void f() {
std::this_thread::sleep_for(std::chrono::seconds(2));
cout << "f(): mid check" << endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
cout << "f(): done" << endl;
}
void fl() {
while (true) {}
cout << "fl() done" << endl;
}
int main() {
std::thread th(f);
thread::native_handle_type handle = th.native_handle();
th.detach();
std::this_thread::sleep_for(std::chrono::seconds(3));
pthread_cancel(handle);
std::thread thfl(fl);
thfl.detach();
handle = thfl.native_handle();
cout << "Handle: " << handle << endl;
pthread_cancel(handle);
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}
/** Output
f(): mid check
Handle: 0
*/
向线程发送终止信号,并不能立即终止线程运行,只有在线程运行到检查点时,才会终止。
std::this_thread
get_id()
std::this_thread::get_id()
sleep_for()
std::this_thread::sleep_for(std::chrono::seconds(1))
线程休眠某个指定的时间片
yield()
std::this_thread::yield
放弃当前线程执行
sleep_until()
template< class Clock, class Duration > void sleep_until( const std::chrono::time_point<Clock,Duration>& sleep_time );
线程休眠至某个指定的时刻,该线程才被重新唤醒
sleep_for
Examples
主线程早于子线程退出
#include <iostream>
#include <thread>
#include <unistd.h>
#include <fstream>
using namespace std;
void f() {
std::this_thread::sleep_for(std::chrono::seconds(1));
cout << "f() finish" << endl;
ofstream out("out", ofstream::out | ofstream::trunc);
if (out.is_open()) {
out << "HELLO";
}
out.close();
return;
}
int main() {
std::thread ths[5];
ths[0] = std::thread();
cout << ths[0].joinable() << endl; // 0
// ths[0].join(); // terminate called after throwing an instance of 'std::system_error'; Invalid argument
ths[1] = std::thread(f);
ths[1].detach();
cout << "main() finish" << endl;
return 0;
}
/** Output
0
main() finish
*/
// 没有打印日志和生成文件
/** 将ths[1].detach()改为ths[1].join()后,Output:
0
f() finish
main() finish
*/
// 有生成文件
子线程会被迫终止
线程作为方法参数
#include <iostream>
#include <thread>
using namespace std;
void fb() {
std::this_thread::sleep_for(std::chrono::seconds(1));
cout << "fb() done" << endl;
}
void f(thread &thd) {
cout << thd.get_id() << endl;
thd.join();
}
void fc(thread thd) {
cout << thd.get_id() << endl;
thd.join();
}
int main() {
thread th1(fb);
thread th2(fb);
cout << th1.joinable() << endl;
cout << th2.joinable() << endl;
f(th1);
// fc(th1); // ERROR: 由于thread禁用了赋值操作符,这里编译时会报错
// 这里的th1是不能拷贝复制给形参的
fc(std::move(th2));
cout << th1.joinable() << endl;
cout << th2.joinable() << endl;
return 0;
}
/** Output
1
1
140432286369536
fb() done
fb() done
140432277976832
0
0
*/
// 一个值得注意的地方,如果main函数改为:
/**
int main() {
thread th1(fb);
f(th1); // 更改了这句的顺序
thread th2(fb);
cout << th1.joinable() << endl;
cout << th2.joinable() << endl;
fc(std::move(th2));
cout << th1.joinable() << endl;
cout << th2.joinable() << endl;
return 0;
}
*/
// 那么输出为
/**
140007787820800
fb() done
0
1
140007787820800
fb() done
0
0
*/
// 有意思的是, 这里的线程ID相同, 有时间再细究, 编译器的优化?
判断线程是否有效
可以通过
joinable
方法判断线程对象有没有被初始化
PS
std::thread::native_handle()
函数只有在调用join()
和detach()
之前有效,之后调用会返回 0,如果此时再调用pthread_cancel()
传入返回值,试图这样来结束改进程(由于返回值是0,并不能结束该线程),会产生core dump#include <iostream> #include <thread> #include <pthread.h> using namespace std; void f() { std::this_thread::sleep_for(std::chrono::seconds(3)); } int main() { std::thread th(f); thread::native_handle_type handle = th.native_handle(); cout << "ID: " << handle << endl; cout << "Handle: " << th.get_id() << endl; th.join(); cout << "Handle: " << th.native_handle() << endl; return 0; } /** Output ID: 139748843316992 Handle: 139748843316992 Handle: 0 */
线程+lambda
#### example 1
$ cat 07.cpp
#include <iostream>
#include <unistd.h>
#include <thread>
using namespace std;
int main() {
thread th([]() {
int i = 0;
while (true) {
cout << "- " << i++ << " -" << endl;
sleep(2);
}
});
th.join();
return 0;
}
$ g++ 07.cpp -lpthread && ./a.out
- 0 -
- 1 -
#### example 2
$ cat 13.cpp
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
using namespace std;
int main() {
std::promise<bool> p;
thread th([&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout << "set value true" << endl;
p.set_value(true);
});
th.detach();
cout << "th detach" << endl;
p.get_future().wait();
cout << "exit" << endl;
return 0;
}
$ g++ 13.cpp -lpthread -std=c++11 && ./a.out
th detach
set value true
exit
参考
编译
g++ -std=c++11 -pthread 002.cpp # g++-4.8
最后更新于
这有帮助吗?