0、thread的成员函数
myjob.join();//阻塞主线程,使得子线程执行完毕之后再执行主线程。
myjob.detach();//解除主线程与子线程的关系,两者独立执行,主线程执行完毕后会自动退出。
joinable();//用于检测线程是否joinable
joinable : 代表该线程是可执行线程。
not-joinable :通常一下几种情况会导致线程成为not-joinable
1) 由thread的缺省构造函数构造而成(thread()没有参数)。
2) 该thread被move过(包括move构造和move赋值)
3) 该线程调用过join或者detach
detach方式下注意事项:
(1)detach()方式时,传指针如果主线程先执行完会发生错误,引用会拷贝不推荐使用。
(2)传递简单数据类型,建议值传递代替引用
(3)传递类对象,避免隐式类型转换,创建线程时使用显示类型转换,并且类对象中函数使用引用。
//std::ref(A)作用:线程传对象时传递参数对象,不进行另外的拷贝
//cout<<"main thread id is : "<
1、互斥量mutex类中有lock() 和unlock()函数、存在多个锁时,加锁顺序一致以防死锁
2、std::lock_guard为类模板,可以取代lock、unlock,可以自己释放锁
//lock_guard构造时调用lock(),析构时调用unlock()
3、std::lock(),锁住两个及两个以上的互斥量。一次加所有锁,要么全加锁要么不加锁。不存在加锁顺序导致死锁的问题
//示例:lock(mutex1,mutex2,…);
4、std::lock_guard()与std::lock()结合使用
//示例:
//std::lock(mutex1,mutex2);
//std::lock_guard guard(mutex1,std::adopt_lock);//使用adpot_lock参数,其为结构体对象
//std::lock_guard guard(mutex2,std::adopt_lock);//使用adpot_lock参数
5、unique_lock是类模板,比lock_guard()更灵活,效率相对低,内存占用高
5.1 初始化参数 adopt_lock(需要提前lock) adpot_lock参数使得构造时不调用mutex的lock函数
示例:
mutex1.lock();
unique_lock guard(mutex1,std::adopt_lock);
5.2 初始化参数std::try_to_lock 在构造unique_lock时尝试加锁,加锁失败则返回,不会阻塞。使用时不能提前加锁
5.3 初始化参数std::defer_lock初始化没有加锁的mutex
6、unique_lock 成员函数
6.1 lock() 不用自己unlock()
6.2 unlock() 用户灵活解锁
6.3 bool try_lock() 尝试加非阻塞锁,加锁成功返回true,加锁失败返回false
6.4 release(),返回它所管理的mutex对象指针,并释放其所有权。解除mutex与unique_lock的联系
7、unique_lock的所有权传递,unique_lock的mutex可以转移,不能复制
//两个unique_lock间转移mutex所有权: unique_lock2(std::move(unique_lock1))
// 通过其他函数返回的unique_lock对象初始化 :
std::unique_lock unique_lock2 = return_lock()//return_lock 返回另一个unique_lock对象
8、sleep 一些毫秒
std::chrono::milliseconds dura(2000);//2秒
std::this_thread::sleep_for(dura);//休息2秒
9、代码Demo
#include
#include
#include
#include
#include
using namespace std;
void myprint(const int &i, char* pmybuf)
{
cout << i << endl;
cout << "main thread id is : " << std::this_thread::get_id() << endl;
cout << pmybuf << endl;
}
class A
{
public:
int val;
A(int s):val(s)
{
cout << "构造" << endl;
}
~A()
{
cout << "析构" << endl;
}
void print(int num)
{
cout << "print num is :" << num << endl;
}
};
class B
{
private:
queue<int> que;
mutex my_mymutex;//互斥量
private:
//删除元素
bool popCore(int &num)
{
my_mymutex.lock();//加锁
if (!que.empty())
{
num = que.front();
que.pop();
my_mymutex.unlock();//解锁
return true;
}
my_mymutex.unlock();//解锁
return false;
}
bool popCore2(int &num)
{
//std::lock_guard guard(my_mymutex);//使用lock_guard
std::unique_lock<std::mutex> guard(my_mymutex);//使用unique_lock
std::chrono::milliseconds dura(2000);//2秒
std::this_thread::sleep_for(dura);//休息2秒
if (!que.empty())
{
num = que.front();
que.pop();
return true;
}
return false;
}
public:
//插入元素
void insert()
{
for (int i = 0; i < 1000; i++)
{
cout << "插入元素 i: " << i << endl;
std::unique_lock<std::mutex> guard(my_mymutex, std::try_to_lock);//使用unique_lock
if (guard.owns_lock())
{
cout << "加锁成功" << endl;
que.push(i);
}
else
cout << "加锁失败" << endl;
}
}
//删除元素对外接口
void pop()
{
int num;
for (int i = 0; i < 1000; i++)
{
if (popCore2(num))
cout << "出队 数字 num :"<< num << endl;
else
cout << "que is NULL" << endl;
}
}
};
int main()
{
/*
int num =10;
char[] buf = "this is a buf";
thread myjob(myprint,num,buf);//可调用函数、对象等,myprint为可调用函数,有参数的话后跟其参数
if (myjob.joinable())
cout << "join true1" << endl;
else
cout << "join false1" << endl;
myjob.join();//阻塞主线程,使得子线程执行完毕之后再执行主线程。
*/
/* lamada表达式作为线程执行对象
auto mylamdathread = [] {
cout << "lamda thread bgein" << endl;
cout << "lamda thread end" << endl;
};
thread myjob2(mylamdathread);
myjob2.join();
cout << "hello" << endl;
*/
/*类成员函数指针做线程执行对象
A myobj(10);
thread myjob4(&A::print,myobj,20);
myjob4.join();
*/
/*创建多个线程,各子线程之间顺序靠操作系统调度
vector threads;
for (int i = 0; i < 10; i++)
threads.push_back(thread(print,i));
for (auto it = threads.begin(); it != threads.end(); ++it)
it->join();
*/
B b;
thread insert_thread(&B::insert, &b);
thread pop_thread(&B::pop, &b);
insert_thread.join();
pop_thread.join();
cout << "hello" << endl;
return 0;
}
条件变量condition_variable、wait、notify_one、notify_all
#include
#include
#include
#include
#include
using namespace std;
class B
{
private:
queue<int> que;
mutex my_mymutex;//互斥量
std::condition_variable my_cond;//条件变量
public:
//插入元素
void insert()
{
for (int i = 0; i < 1000; i++)
{
std::unique_lock<std::mutex> guard(my_mymutex);//使用unique_lock
cout << "插入元素 i: " << i << endl;
que.push(i);
my_cond.notify_one();//通知一个线程唤醒wait的线程
//notify_all()通知所有线程唤醒wait的线程,唤醒的多个线程争用锁
}
}
//删除元素对外接口
void pop()
{
int num = 0;
while (true)
{
std::unique_lock<std::mutex> guard(my_mymutex);
//wait()没有第二个参数或第二个参数返回false则解锁互斥量,阻塞;直到其他线程调用notify_one()函数
my_cond.wait(guard, [this] {//lambda表达式
if (!que.empty())
return true;
return false;
});
num = que.front();
que.pop();
guard.unlock();//灵活释放锁,可由unique_lock对象析构时释放
cout << "出队元素为:" <<num << endl;
}
}
};
int main()
{
B b;
thread insert_thread(&B::insert, &b);
thread pop_thread(&B::pop, &b);
insert_thread.join();
pop_thread.join();
cout << "hello" << endl;
return 0;
}
原子操作、std::async()使用
1、std::async为函数模板,返回std::future类对象 作用为创建异步任务
(1)参数std::launch::deferred表示任务等待get()或wait()时执行,延迟调用,不创建线程,主线程中执行
示例:std::future result = std::async(std::launch::deferred,mythread)
(2)参数std::launch::async调用async()时创建执行子线程异步执行
(3)std::launch::async | std::launch::deferred,首先创建新线程异步执行,创建失败时则延迟主线程执行
2、std::packaged_task 打包任务,类模板
示例:std::packaged_task
3、std::promise类模板,在某个线程中给它赋值,其他线程中可以使用
4、std::future result = std::async(mythread,10);
std::future_status status = result.wait_for(std::chrono::seconds(1));//等待1s返回枚举类型
std::future_status:
(1)ready ,线程执行完毕
(2)timeout,超时,线程未执行完毕
(3)deferred,async的第一个参数设置为std::launch::deferred,由主线程延迟执行
5、可以定义为原子操作的运算符:++、–、+=、-=,&=、|=等
//定义全局变量
std::atomic num;//原子操作对象
(1)atomic的load()函数以原子方式读 auto num2 (num.load());
(2)atomic的store()函数以原子方式写 num2.store(123);
#include
#include
#include
#include
#include
#include
using namespace std;
//全局变量
std::atomic<int> num;//原子操作对象
int mythread(int num)
{
cout << "thread begin, thread id is :" << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(2000);//休息2秒
std::this_thread::sleep_for(dura);
cout << "thread end" << endl;
return 5;
}
//promise类模板使用,在某个线程中给它赋值,其他线程中可以使用
void func(std::promise<int> &temp, int calc)
{
calc++;
calc *= 10;
std::chrono::milliseconds dura(2000);//休息5秒
std::this_thread::sleep_for(dura);
int result = calc;
temp.set_value(result);
}
//原子操作演示
void addNum()
{
for (int i = 0; i < 1000; i++)
num++;//atomic对象的操作是原子操作
}
int main()
{
int num = 3;
cout << "main thread id is :" << std::this_thread::get_id() << endl;
//1、std::async为函数模板,返回std::future类对象 作用为创建异步任务
std::future<int> result = std::async(mythread,num);//以mythread()为执行对象创建一个后台线程,此时不会阻塞
//std::future result = std::async(mythread);//async(&A::func,&a,参数),
//A类的成员函数func做执行对象,a为A的对象,参数为func的参数
//2、(1)参数std::launch::deferred表示任务等待get()或wait()时执行
//延迟调用,不创建线程,主线程中执行
//示例:std::future result = std::async(std::launch::deferred,mythread)
//(2)参数std::launch::async调用async()时创建执行子线程
//(3)std::launch::async | std::launch::deferred,首先创建新线程异步执行,创建失败时则延迟主线程执行
cout << result.get() << endl;//阻塞直到result返回结果,get函数只能调用一次
cout << "结束" << endl;
/*
//3、std::packaged_task 打包任务,类模板
//std::packaged_task mypt(mythread);
std::packaged_task mypt([](int num) {//包装lambda表达式
cout << "thread begin, thread id is :" << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(1000);//休息1秒
std::this_thread::sleep_for(dura);
cout << "thread end" << endl;
return 5;
});
std::thread t1(std::ref(mypt), 1);
t1.join();
std::future result = mypt.get_future();
cout << result.get() << endl;
*/
/*
//std::promise类模板,在某个线程中给它赋值,其他线程中可以使用
std::promise myprom;
std::thread t1(func,std::ref(myprom), 10);
t1.join();
std::future result = myprom.get_future();
auto res = result.get();
cout << "result : " << res << endl;
cout << "结束" << endl;
*/
/*
//4、
std::future result = std::async(mythread,10);
std::future_status status = result.wait_for(std::chrono::seconds(1));//等待1s返回枚举类型
if (status == std::future_status::timeout)//表示超时,线程未执行完
{
cout << "超时,线程未执行完" << endl;
}
else if (status == std::future_status::ready)//表示线程成功返回
{
cout << "线程执行完毕,返回" << endl;
cout << result.get() << endl;
}
else if (status == std::future_status::deferred)
{
//async的第一个参数设置为std::launch::deferred
cout << "线程延迟执行" << endl;
cout << result.get() << endl;
}
*/
/*
//5、shard_future 类模板,get()复制数据,可以get多次
std::packaged_task mypt(mythread);
std::thread t1(std::ref(mypt), 10);
t1.join();
std::future result = mypt.get_future();
bool isValid = result.valid();
if(isValid)
cout<<"result valid"< shared_res(result.share()); //等价于std::move(result)
//上述5行可以代替为:
//std::shared_future res(mypt.get_future());
isValid = result.valid();
if (!isValid)
{
cout << "result unvalid" << endl;
isValid = shared_res.valid();
cout << "get result :" << shared_res.get() << endl;
cout << "get result :" << shared_res.get() << endl;
cout << "get result :" << shared_res.get() << endl;
}
*/
/*
//6、原子操作std::atomic
//全局变量num定义为atomic对象
thread t1(addNum);
thread t2(addNum);
t1.join();
t2.join();
cout << num << endl;
*/
return 0;
}