c++11推出的封装类,网上说法褒贬不一,有说让线程简单很多的,而且跨平台的,也有说这个写的很多功能不该做,或者该有的功能没写
linux底下编程可能会更推荐用Pthreads ?或者两个结合一起使用
反正刚转语言,啥都不懂,都研究一下。。
1.调用类内方法,带参数及不带参数
class ThreadTest {
public:
static void f1() {
int cnt = 5;
while (--cnt > 0)
{
cout << " Calling Function f1 " << endl;
Sleep(1000);
}
};
static void f2(int& input) {
int cnt = 5;
while (cnt-- > 0)
{
cout << " Calling Function f2 input:" << input << endl;
Sleep(1000);
}
};
void test1() {
thread t1(f1);//f1:类内静态方法
int input = 2;
thread t2(f2, ref(input));//f2:类内静态带参方法
t1.join();
t2.join();
}
}
2.调用类内非静态方法:传入实例及通过类名引用
class ThreadTest {
public:
void f3() {
cout << "Calling Function this::f3 " << endl;
};
void f4(int input) {
cout << "Calling Function this::f4 , input :" << input << endl;
};
void test1() {
thread t3(&ThreadText::f3, this);
thread t4(&ThreadText::f4, this, 4);
t3.join();
t4.join();
}
}
3.通过lambda调用匿名函数,或在匿名函数中调用其他函数
[]内捕捉的变量是非静态的,(静态且访问级别足够的不需要捕捉)
class ThreadTest {
public:
void f6(int input) {
cout << "Calling Function this::f6 , input :" << input << endl;
};
void test1() {
int i = 5;
thread t5([i] {
cout << "Calling Function f" << i << " with Lambda" << endl;
});
i = 6;
thread t6([this, i] {
f6(i);
});
t5.join();
t6.join();
}
}
4.detach 和 join:
区别:
join会阻塞当前线程,直至子线程全部完成,当前线程才允许结束
detach则不会,和当前线程没有任何关系独立运行,直至自身结束或程序结束
无论是join 还是detach,调用之后joinable()均为false
class ThreadTest {
public:
void f7() {
int Cnt = 500;
while (--Cnt >= 0) {
cout << "Calling Function f7 , left Time :" << Cnt << endl;
Sleep(1000);
}
};
static void f8() {
int Cnt = 5;
while (--Cnt >= 0) {
cout << "Calling Function f8 , left Time :" << Cnt << endl;
Sleep(1000);
}
}
void test1() {
thread t7(&ThreadText::f7, this);
thread t8(&ThreadText::f8);//这样写也是可以的,等价直接写f8
t7.detach();
t8.join();
}
};
结果:t7还没跑完,但是t8先跑完了,test1方法结束,main中调用完之后结束,t7随之也结束了
关于join的阻塞问题:
示例如下:
class ThreadJoinTest {
public:
void test() {
thread t1([] {
Sleep(5000);
cout << "t1Function has been Excute" << endl;
});
thread t2([] {
Sleep(3000);
cout << "t2Function has been Excute" << endl;
});
thread t3([] {
Sleep(1000);
cout << "t3Function has been Excute" << endl;
});
t1.join();
t2.join();
t3.detach();
thread t4([] {
Sleep(50000);
cout << "t4Function has been Excute" << endl;
});
t4.detach();
thread t5([] {
Sleep(1000);
cout << "t5Function has been Excute" << endl;
});
t5.join();
cout << "test end" << endl;
}
};
结论是:join不会阻塞当前线程的其他子线程的实例化或join或detach?
再改一下代码:
class ThreadJoinTest {
public:
void test() {
thread t1([] {
Sleep(5000);
cout << "t1Function has been Excute" << endl;
});
thread t2([] {
Sleep(3000);
cout << "t2Function has been Excute" << endl;
});
thread t3([] {
Sleep(1000);
cout << "t3Function has been Excute" << endl;
});
t1.join();
t2.join();
t3.detach();
thread t4([] {
Sleep(50000);
cout << "t4Function has been Excute" << endl;
});
t4.detach();
thread t5([] {
Sleep(10000);
cout << "t5Function has been Excute" << endl;
});
t5.join();
cout << "do nothing" << endl;
thread t6([] {
Sleep(1000);
cout << "t6Function has been Excute" << endl;
});
t6.join();
cout << "test end" << endl;
}
};
t5 join之后等了足足10秒才打印do nothing,即对线程相关的操作是不阻塞的?遇到当前线程的其他操作才会阻塞?
5.condition_variable_any,condition_variable 和 mutex
当存在多个线程,你想将这些线程按照指定的规律执行,可以通过很多方法,比如信号量,互斥锁,条件变量等实现
当不需要按照某些特定顺序时,保持数据的一致性即可时,可以通过互斥锁mutex:
mutex.lock();
mutex.unlock();
当需要按照某些特定顺序,比如leetCode中的FooBar问题等,就需要用到条件变量
另一个情景:当存在5个线程,你想将这五个线程按顺序从10到1的顺序打印,并且是交替打印,即5个线程按顺序打印出10,再按顺序打出9直到1时,就需要条件变量
class ThreadMutexTest {
public:
int t;
condition_variable_any cv;
/*condition_variable cv;*/
mutex m;
ThreadMutexTest() {
t = 0;
}
void fn(int Cnt, int n, int max) {
while (Cnt > 0)
{
lock_guard<mutex> locker(m);
cv.wait(m, [n, this] {return t == n; });
t = (t + 1) % max;
cout << "Function f" << n + 1 << " printline Cnt:" << Cnt << endl;
cv.notify_all();
Cnt--;
}
}
void test() {
vector<thread> v;
for (int i = 0; i < 5; i++)
v.emplace_back(&ThreadMutexTest::fn, this, 10, i, 5);//转移构造,比push_back少了拷贝,减少开辟临时变量空间
for_each(v.begin(), v.end(), std::mem_fn(&std::thread::join));
}
};
结果:
使用步骤:
声明lock_guard/unique_lock (上锁,等价于mutex.lock() .unlock(),但是更可靠,在一组括号中会自动的调用析构函数确保unlock得到执行,避免使用mutex出现忘记或者异常抛出导致的没有unlock而出现的死锁)
详情直接贴另一位大佬的链接:
C++锁的管理-- std::lock_guard和std::unique_lock
lock_guard<mutex> locker(m);
等待获取锁,wait(锁,lambda表达式),指定获取锁的条件
cv.wait(m, [n, this] {return t == n; });
通知其他等待的线程,让他们来抢锁
cv.notify_all();
上边只用到了condition_variable_any
如果同样的代码,仅将condition_variable_any 改为 condition_variable
则会报错:
改成如下:
class ThreadMutexTest {
public:
int t;
condition_variable cv;
/*condition_variable_any cv;*/
mutex m;
ThreadMutexTest() {
t = 0;
}
void fn(int Cnt, int n, int max) {
while (Cnt > 0)
{
unique_lock <mutex> locker(m);
cv.wait(locker, [n, this] {return t == n; });
t = (t + 1) % max;
cout << "Function f" << n + 1 << " printline Cnt:" << Cnt << endl;
cv.notify_all();
Cnt--;
}
}
void test() {
vector<thread> v;
for (int i = 0; i < 5; i++)
v.emplace_back(&ThreadMutexTest::fn, this, 10, i, 5);//转移构造,比push_back少了拷贝,减少开辟临时变量空间
for_each(v.begin(), v.end(), std::mem_fn(&std::thread::join));
}
};
结果也是一样的,和上一段区别在:
lock_guard变成了unique_lock
cv.wait里从mutex实例 变成了 unique_lock实例
除此之外这两个用法好像差不多
还是直接贴另一个大佬的链接,这边就不过多的介绍了:
C++11并发编程-条件变量(condition_variable)详解
6.其他:
1.Sleep && sleep_until && sleep_for
Sleep(毫秒数,这个就不提了)
this_thread::sleep_until (chrono::system_clock::time_point)
或
this_thread::sleep_for(chrono::system_clock::seconds(xxx))
(或其他时间单位)
可以控制具体的睡眠时间
2.thread::swap(thread &Other)
和另一个线程交换上下文
等价于
swap(thread &Left,thread &Right);
3.move(thread &t)
构造函数
参数被move之后就不再是线程了。相当于把参数中的线程上下文“抢”了过来
4.get_id()
如果线程是joinable的,则会返回一个id(其实就是个无符号32位?)
当已经执行过了,或者被move走了等,即joinable==false时,返回的是0
class ThreadOtherTest {
public:
thread h;
thread w;
void hello() {
cout << "Hello";
}
void World() {
cout << " World" << endl;
}
void test() {
thread hellothread(&ThreadOtherTest::hello, this);
hellothread.swap(h);
h.join();
thread worldthread(&ThreadOtherTest::World, this);
swap(w, worldthread);
w.join();
thread m([] {
auto tp = chrono::system_clock::now();
tp += chrono::seconds(4);
this_thread::sleep_until(tp);
this_thread::sleep_for(chrono::seconds(1));
cout << "test" << endl;
int t = 0;
while (t++ < 10) {
cout << "Sleeping" << endl;
Sleep(1000);
}
});
cout << "m id:" << m.get_id() << endl;
thread m2(move(m));
cout << "after m2 move(m)" << m.get_id() << endl;
cout << "mainid:" << this_thread::get_id() << endl;
cout << "m2id:" << m2.get_id() << endl;
m2.join();
cout << "after m2 join" << m2.get_id() << endl;
}
};