一.join和detach
C++中的thread对象通常来说表达了执行的线程(thread of execution),这是一个操作系统或者平台的概念。
当thread::join()函数被调用后,调用它的线程会被block,直到线程的执行被完成。基本上,这是一种可以用来知道一个线程已结束的机制。当thread::join()返回时,操作系统的执行的线程已经完成,C++线程对象可以被销毁。
当thread::detach()函数被调用后,执行的线程从线程对象中被分离,已不再被一个线程对象所表达--这是两个独立的事情。C++线程对象可以被销毁,同时OS执行的线程可以继续。如果程序想要知道执行的线程何时结束,就需要一些其它的机制。join()函数在那个thread对象上不能再被调用,因为它已经不再和一个执行的线程相关联。
去销毁一个仍然可以“joinable”的C++线程对象会被认为是一种错误。为了销毁一个C++线程对象,要么join()函数需要被调用(并结束),要么detach()函数被调用。如果一个C++线程对象当销毁时仍然可以被join,异常会被抛出。
因此,你应该在执行流程到析构函数前总是要么join,要么detach一个线程
https://www.cnblogs.com/LuckCoder/p/10950583.html
void function_1() {
cout << "函数function_1\n";
}
int main() {
thread t1(function_1);
//t1.join();
t1.detach();
if (t1.joinable()) {
t1.join();
}
return 0;
}
二.ref move
string s = "Main";
thread t1(Fctor(), s);
t1.join();
thread t2(Fctor(), ref(s));
t2.join();
thread t3(Fctor(), move(s));
t3.join();
thread t4 = move(t3);
cout << this_thread::get_id() << endl;
cout << t3.get_id() << endl;
cout << _Thrd_hardware_concurrency() << endl; //线程最大数
三.lock lock_guard unique_lock
lock:
void shared_print1(string id, int value) {
m_mutex1.lock();
cout << "From " << id << " " << value << endl;
m_mutex1.unlock();
}
lock_guard:
void shared_print1(string id, int value) {
// 顺序不一样会发生死锁
lock_guard<mutex> locker2(m_mutex2);
lock_guard<mutex> locker1(m_mutex1);
cout << "From " << id << " " << value << endl;
}
void shared_print2(string id, int value) {
lock_guard<mutex> locker1(m_mutex1);
lock_guard<mutex> locker2(m_mutex2);
cout << "From " << id << " " << value << endl;
}
要么使用lock函数:
lock(m_mutex1, m_mutex2);
unique_lock:
用法更加灵活,但占用更多cpu
void shared_print1(string id, int value) {
unique_lock<mutex> locker(m_mutex1, defer_lock);
//..
locker.lock();
cout << "From " << id << " " << value << endl;
locker.unlock();
//..
locker.lock();
//....
locker.unlock();
// 只能移动不能复制
unique_lock<mutex> locker2 = move(locker);
}
四.call_once
有些代码我们只进行一次,第一种需要不断加锁,第二种只会执行一次
{
unique_lock<mutex> locker(m_mutex1, defer_lock);
if (!f.is_open()) {
f.open("log.txt");
}
}
call_once(m_flag, [&]() {f.open("log.txt"); });
五.条件变量condition_variable
牵扯到解锁,只能用unique_lock
https://www.cnblogs.com/GuoXinxin/p/11675053.html
deque<int> q;
mutex mu;
condition_variable cond;
void function_1() {
int count = 10;
while (count > 0) {
unique_lock<mutex> locker(mu);
q.push_back(count);
locker.unlock();
cond.notify_one();
//cond.notify_all(); //激活所有线程
this_thread::sleep_for(chrono::seconds(1));
count--;
}
}
void function_2() {
int data = 0;
while (data != 1) {
unique_lock<mutex> locker(mu);
cond.wait(locker, []() {return !q.empty(); });
data = q.back();
q.pop_back();
locker.unlock();
cout << "t2 got a value from t1 : " << data << endl;
}
}
int main() {
thread t1(function_1);
thread t2(function_2);
t1.join();
t2.join();
生产者消费者问题:
list<int> q;
mutex mu;
condition_variable cond;
int flag;
void function_1() {
int count = 0;
while (count < 10) {
unique_lock<mutex> locker(mu);
q.push_back(count);
cout << "生产: " << count << endl;
locker.unlock();
cond.notify_one();
count++;
}
flag = 1;
}
void function_2() {
int tmp;
while (1) {
unique_lock<mutex> locker(mu);
cond.wait_for(locker, chrono::seconds(1) ,[]() {return !q.empty(); });
if (flag && q.empty()) {
break;
}
tmp = q.front();
q.pop_front();
cout << "消费: " << tmp << endl;
locker.unlock();
}
}
int main() {
thread t1(function_1);
thread t2(function_2);
t1.join();
t2.join();
六.future promise async
https://blog.csdn.net/jiange_zh/article/details/51602938
int factorial(future<int>& fu) {
int res = 1;
int N = fu.get();
for (int i = 1; i <= N; i++) res *= i;
return res;
}
int main() {
promise<int> p;
future<int> fu = p.get_future();
future<int> fu1 = async(launch::async, factorial, ref(fu));
p.set_value(4);
int x = fu1.get();
cout << "Get from child: " << x << endl;
future:
可以处理所有在线程间数据转移的必要同步,但是future模型独享同步结果的所有权。并且通过 get() 函数,一次性的获取数据,让并发访问变的毫无意义。你的并发代码没有办法让多个线程等待同一个事件。
可以完成让多个线程的等待
promise<int> p;
future<int> fu = p.get_future();
shared_future<int> sf = fu.share();
future<int> fu1 = async(launch::async, factorial, sf);
future<int> fu2 = async(launch::async, factorial, sf);
future<int> fu3 = async(launch::async, factorial, sf);
七.创建线程的几种方式
https://blog.csdn.net/mmk27_word/article/details/108187405
八.packaged_task
九:时间约束
thread t1(factorial, 5);
this_thread::sleep_for(chrono::milliseconds(3)); //时间段
chrono::steady_clock::time_point tp = chrono::steady_clock::now() + chrono::milliseconds(3);
this_thread::sleep_until(tp); // 时间点
mutex mu;
unique_lock<mutex> locker(mu);
locker.try_lock_for(chrono::microseconds(3));
locker.try_lock_until(tp);
condition_variable cond;
cond.wait_for(locker, chrono::microseconds(3));
cond.wait_until(locker, tp);
promise<int> p;
future<int> f = p.get_future();
f.wait_for(chrono::microseconds(3));
f.wait_until(tp);