c++11 std::thread和mutex用法
- thread和mutex用法
- thread简单示例
- thread构造函数梳理
- thread关键成员函数
- mutex使用
thread和mutex用法
本文对c++ 11中的std::thread 和 mutex作简要的使用说明
thread简单示例
#include <iostream>
#include <string>
#include <thread>
using namespace std;
void thread_hello_wolrd()
{
cout << "hello world!" << endl;
}
void thread_any_word(string&str)
{
cout << str << endl;
}
int main()
{
thread t_hello(thread_hello_wolrd);
t_hello.join(); //等待t_hello子线程结束,才继续下面的操作
string str = "hello my world!";
thread t_any_word(thread_any_word, std::ref(str));
t_any_word.detach(); //t_any_world子线程与主线程分离,即使主线程结束,也会运行
return 0;
}
thread构造函数梳理
thread() _NOEXCEPT:默认构造函数,创建的是空thread对象
explicit thread(_Fn&& _Fx, _Args&&… _Ax):可变参数的构造函数,该线程是可jointable的
thread(const thread&) = delete;拷贝构造函数不可用
thread(thread&& _Other) _NOEXCEPT:移动构造函数,使用之后,other线程为空,移交给当前thread
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void fun1(int n)
{
for (int i = 0; i < 10; i++)
{
cout << "fun1:" << n << endl;
this_thread::sleep_for(chrono::microseconds(10));
}
}
void fun2(int& n)
{
for (int i = 0; i < 10; i++)
{
cout << "fun2:" << n << endl;
++n;
this_thread::sleep_for(chrono::microseconds(10));
}
}
int main()
{
int n = 0;
thread t1;
thread t2(fun1, n);
thread t3(fun2, std::ref(n));
thread t4(move(t3)); //t3线程为空
t2.join();
t4.join();
cout << "result n =" << n << endl;
return 0;
}
thread关键成员函数
- get_id():获取线程id
- joinable(): 判断线程是否可joinable()
joinable()函数是一个布尔类型的函数,他会返回一个布尔值来表示当前的线程是否是可执行线程(能被join或者detach),因为相同的线程不能join两次,也不能join完再detach,同理也不能detach,所以joinable函数就是用来判断当前这个线程是否可以joinable的。通常不能被joinable有以下几种情况:
1)由thread的缺省构造函数而造成的(thread()没有参数:
2)该thread被move过(包括move构造和move赋值):
3)该线程被join或者detach过。 - detach(): 将当前线程脱离主线程,线程可以单独执行
- swap(): 交换两线程的句柄
- std::this_thread::getid():获取当前线程id
- std::this_thread::yield(): 当前线程放弃执行,调度另一线程继续执行
- sleep_until(): 线程休眠至某时刻被唤醒
- sleep_for(): 线程休眠时间片后被唤醒
mutex使用
多个线程访问共享资源时,需要加锁互斥访问
- 独占式互斥量:std::mutex独占工互斥量加解锁是成对的,同一个线程内独占式互斥量在没有解锁的情况下,再次对其加锁是不正确的。
- 递归式互斥量:std::recursive_mutex 递归式互斥量是在同一个线程内互斥量没有解锁的情况下可以再次对其加锁,但其加解锁的次数需要保持一致。
- 允许超时的独占式互斥量: std::time_mutex
- 允许超时的递归式互斥量: std::recursive_time_mutex
#include<iostream>
#include <thread>
#include <mutex>
using namespace std;
int total_num = 0;
std::mutex mtx;
void fun1()
{
for (int i = 0; i < 500; i++)
{
mtx.lock(); //对异常抛出的情况,会发生死锁
cout << "fun1:" << total_num++ << endl;
mtx.unlock();
this_thread::sleep_for(chrono::microseconds(10));
}
}
void fun2()
{
for (int i = 0; i < 500; i++)
{
{
std::lock_guard<mutex>gd(mtx); //可以防止死锁,更安全,作用域有效
cout << "fun2:" << total_num++ << endl;
}
this_thread::sleep_for(chrono::microseconds(10));
}
}
int main()
{
std::thread t1(fun1);
std::thread t2(fun2);
t1.join();
t2.join();
return 0;
}
若线程1对共享资源的访问时间过长,而线程2又不想等那么久,可以设定一个超时时间 ,在超时时间内若线程1中的互斥量还没有解锁,线程2就继续向下执行,这就是允许超时的互斥量。lock_guard只是提供了对互斥量最基本的加解锁封装,而unique_lock提供了多种构造方法,使用起来更加灵活,对于允许超时的互斥量需要使用unnique_lock来包装。
#include <iostream>
#include <thread>
#include <mutex>
#include <Windows.h>
using namespace std;
timed_mutex mtx;
void fun1()
{
unique_lock<timed_mutex> t1(mtx);
Sleep(2000); //模拟其他事项占用了大量时间
cout << "fun1" << endl;
}
void fun2()
{
unique_lock<timed_mutex> t1(mtx, chrono::milliseconds(1000));//设置超时时间为1秒
cout << "fun2" << endl;
}
int main(int argc, char* argv[])
{
thread t1(fun1);
Sleep(100); //让线程1先启动
thread t2(fun2);
t1.join();
t2.join();
return 0;
}