文章目录
https://www.bilibili.com/video/BV1Yb411L7ak
第一节
单核CPU:执行多个任务要不停的切换(切换有额外时间开销)
多核(可硬件并发):核数=并行任务数
C++11之前的多线程缺点非常多,也不可跨平台
并发:程序同时执行多个任务,提高程序运行效率
实现并发方法:创造多个进程(多进程并发)、在单个进程中创建多个线程(多线程并发),可混合使用,但是建议优先使用多线程:线程相互间切换和启动速度快、系统资源开销小、速度快
进程:运行一个可执行程序.exe,就叫创建进程
线程:用来执行代码,指一条代码的执行道路
多线程(并发):各需要独立的堆栈空间(1M),相互切换有时间开销(根据需要开线程数,一般最高200-300),其中某个线程堵住了,其他线程也可照常执行
一个进程有且只有一个主线程,随进程启动结束自动启动结束(main的开始结束处)
一个进程中的所有线程共享内存,开销远小于多进程,但有数据一致性问题相互覆盖
不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
同一进程下不同线程间数据很易共享(同一火车(进程)中,A车厢换到B车厢很容易)
进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。"互斥锁":火车上的洗手间
进程使用的内存地址可以限定使用量。“信号量”:火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去
并发:指程序运行时的状态(同时运行);类似单个 CPU ,通过 CPU 调度算法等,使得不同的代码块交替执行,处理多个任务的能力,来实现并发的假象(不是真正的并发),切换任务时要保存变量的状态、执行进度等,存在时间开销
并行:程序的结构(程序同时执行多个独立的任务);类似多个 CPU ,同时并且处理相同多个任务的能力,不同的代码块同时执行
一个进程中的所有线程共享地址空间(共享内存),全局变量、全局内存、全局引用都可以在线程之间传递,所以多线程开销远远小于多进程
多进程并发核多线程并发可以混合使用,但建议优先考虑多线程技术
多核CPU:能够实现真正的并行执行多个任务(硬件并发)
在C++11之前,C/C++一直是一种顺序(串行执行)的编程语言。而在C++11可以进行线程编程,不再依赖第三方库
第二节
进程是否执行完毕的标志是:主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完
了,一般来说,此时如果其他子线程还没有执行完,也会被强行终止
#include<iostream>
#include<string>
#include<thread>
using namespace std;
/* 函数法创建子线程 */
void t1()
{
cout << "subthread1 " << endl;
cout << "subthread2 " << endl;
cout << "subthread3 " << endl;
}
int main()
{
thread a(t1); //(thread 是一个类) 创建子线程( t1()),并开始执行;thread a = thread(t1);
if (a.joinable()) //joinable()判断此处能不能调用函数join() 或 detach()。返回 ture:可以调用join()或detach()
{
cout << " joinable1() = ture, you can use join() or detach() " << endl;
}
a.join(); //阻塞:主线程等子线程结束才跳出这句,并回收子线程资源;如果线程函数有返回值,则忽略返回值
// a.detach(); //主、子线程穿插运行。主线程可能比子线程结束先结束,所以t1()不会全部显示出来;将线程和线程对象分离,线程何时执行完我们也无法控制
//此时,子线程在后台运行,被c++运行时库接管,执行结束后,由运行时库清理该线程的相关资源;之后就再也无法控制子线程了,线程何时执行完我们也无法控制
//detach()和join()不能同时用,建议一般使用join()
if (a.joinable())
{
cout << " joinable2() = ture, you can use join() or detach() " << endl;
}
cout << " mainthread1 " << endl;
cout << " mainthread2 " << endl;
cout << " mainthread3 " << endl;
return 0;
}
///
/*用类创建子线程*/
class T
{
public:
void operator() () //类中包含operator()就变成了可调用对象。operator重载括号(不带参数):作为线程的入口函数
{
cout << "subthread1 " << endl;
cout << "subthread2 " << endl;
cout << "subthread3 " << endl;
}
};
int main()
{
T t;
thread a(t);
a.join();
//a.detach();
cout << " mainthread " << endl;
return 0;
}
///
// 使用detach()要注意:类中是对my_i的引用,当主线程结束时,对my_i回收销毁,然而子线程中还在用my_i,所以要借助join()等待
class T
{
public:
T(int& i) : m_i(i) {}
// T(const T& t) : m_i(t.m_i)
// {
// cout << " T()拷贝构造被执行 " << endl;
// }
~T()
{
cout << " `T()析构被执行 " << endl;
}
void operator() ()
{
cout << " subthread " << endl;
}
int& m_i;
};
int main()
{
int my_i = 6;
T t(my_i); //引用
thread a(t);
cout << " up of join()" << endl;
a.join();
// a.detach();
cout << " down of join()" << endl;
cout << " mainthread " << endl;
return 0;
}
/
// 类对象t为main内局部变量,主线程结束时要被销毁。然而:因为T类对象没有被引用,t实际会调用赋值构造函数,所以可以detach()
class T
{
public:
T(int& i) : m_i(i) {
cout << " T()构造 " << endl;
}
T(const T& t) : m_i(t.m_i)
{
cout << " T()拷贝构造被执行 " << endl;
}
~T()
{
cout << " `T()析构被执行 " << endl;
}
void operator() ()
{
cout << "subthread1 " << endl;
cout << "subthread2 " << endl;
cout << "subthread3 " << endl;
}
int& m_i;
};
int main()
{
int my_i = 6;
T t(my_i);
thread a(t); //拷贝构造被调用:说明t被复制到子线程中
a.detach(); //t被析构(而子线程中复制出的对象在后台析构,不在控制台显示)
//a.join(); //控制台显示析构了两次(先析构子线程)
cout << " mainthread " << endl;
return 0;
}
/
/*lamda表达式创建线程*/
int main()
{
auto lambdaThread = [] {
cout << " subthread1 " << endl;
cout << " subthread2 " << endl;
};
thread a(lambdaThread);
a.join();
//a.detach();
cout << " mainthread " << endl;
}
第三节
#include<iostream>
#include<string>
#include<thread>
using namespace std;
//使用detach(),在子线程函数中:引用变量为深拷贝,指针参数为浅拷贝
void myPrint(const int& a, char* b)
//void myPrint(const int a, const string& b) //传递简单的数据类型,建议都是值传递(引用会被误视为浅拷贝)
{
cout << "subthread: " << a << ", a.address=" << &a << endl;
cout << "subthread: " << b << endl;
}
int main()
{
int a = 1;
char mybuf[] = "this is a test";
thread myThread(myPrint, a, mybuf); //参数:函数名,函数的第一个参数,函数的第二个参数。a为假引用?(深拷贝到子线程临时地址); char* b 为指针(地址不变),所以detach不安全
a = 10;
cout << " mainthread " << a << ", a.address=" << &a << endl;
//myThread.detach();
myThread.join();
cout << " mainthread " << a << ", a.address=" << &a << endl;
return 0;
}
//使用detach(),在子线程函数的参数存在类型转换时,要在创建线程的同时转换类型
void myPrint(const int& a, const string& b)
{
cout << a << endl;
cout << b << endl;
}
int main()
{
int a = 1;
char mybuf[] = "mybuf";
//thread myThread(myPrint, a, mybuf); //隐含类型转换 char -> string
//当时上行对应使用detach()时(err): 传入mybuf后,子线程中将mybuf转为string类型前,可能原地址已被销毁?
//所以:传入mybuf前先转换类型(存在类型转换都要在主线程中先转换)
thread myThread(myPrint, a, string(mybuf));
myThread.detach();
cout << " mainthread " << endl;
return 0;
}
//以上两个问题在使用 join() 时不存在
/*验证上方问题的解决方式正确性*/
class A {
public:
A(int i) : m_i(i) { cout << "构造函数执行" << this << endl; }
A(const A& a) : m_i(a.m_i) { cout << "拷贝构造函数执行" << this << endl; }
~A() { cout << "析构函数执行" << this << endl; }
int m_i;
};
void myPrint(const A& pmybuf) //实为深拷贝,函数参数使用引用,否则会多构造一次对象(共3次)
{
cout << &pmybuf << endl;
}
int main()
{
int mvar = 1;
//thread myThread(myPrint, mvar); //err,终端未输出A的构造函数信息(说明在main结束前,仍未转为A类型对象)
thread myThread(myPrint, A(mvar)); //终端输出拷贝信息(说明在主线程中拷贝),拷贝完临时对象A(mvar)后,立即析构临时对象
myThread.detach();
cout << " mainthread " << endl;
}
/*再次验证*/
class A {
public:
A(int i) : m_i(i) { cout << " 构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
A(const A& a) : m_i(a.m_i) { cout << " 拷贝构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
~A() { cout << " 析构函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
int m_i;
};
void myPrint(const A& pmybuf)
{
cout << " 子线程参数地址" << &pmybuf << " threadId= " << this_thread::get_id() << endl;
}
int main()
{
cout << " 主线程Id是:" << " threadId= " << this_thread::get_id() << endl; //get_id():获取当前正在运行的线程的id
int mvar = 1;
cout << "myThread(myPrint, mvar)" << endl;
thread myThread(myPrint, mvar); //终端中可看到:临时对象在子线程中创建
cout << "myThread.get_id: " << myThread.get_id() << endl; //获取线程myThread的id
myThread.join();
//myThread.detach();
cout << endl << "myThread(myPrint, A(mvar))" << endl;
thread myThread2(myPrint, A(mvar)); //终端中可看到:临时对象在主线程中创建
myThread2.join();
//myThread.detach();
cout << "cup num = " << thread::hardware_concurrency() << endl;//获取cpu核心数,失败返回0
return 0;
}
class A {
public:
A(int i) : m_i(i) { cout << " 构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
A(const A& a) : m_i(a.m_i) { cout << " 拷贝构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
~A() { cout << " 析构函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
mutable int m_i;
};
void myPrint(const A& pmybuf) //深拷贝
{//引用必须加 const,没有原因。类 A 中使用mutable:任何情况下成员变量 m_i 都可以修改
pmybuf.m_i = 199;
cout << "子线程参数地址" << &pmybuf << " threadId= " << this_thread::get_id() << endl;
}
int main()
{
A myobj(10);//调试到跳出子线程可发现,主线程中的myobj没有在子线程中被修改,仍然是10
thread myThread(myPrint, myobj); //在主线程中深拷贝,拷贝到子线程中的地址
myThread.join();
return 0;
}
/*std::ref():实现真正的引用;在子线程中实现对主线程中成员变量的修改*/
class A {
public:
A(int i) : m_i(i) { cout << " 构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
A(const A& a) : m_i(a.m_i) { cout << " 拷贝构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
~A() { cout << " 析构函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
int m_i;
};
void myPrint(A& pmybuf) // 用ref(),const 就可以删去了,则mutable也可以不要了
{
pmybuf.m_i = 199;
cout << "子线程参数地址" << &pmybuf << " threadId= " << this_thread::get_id() << endl;
}
int main()
{
A myobj(10);
thread myThread(myPrint, std::ref(myobj)); //子线程中直接引用,不再调用拷贝构造
myThread.join();
cout << myobj.m_i << endl;
return 0;
}
/*传递智能指针给子线程*/
class A {
public:
A(int i) : m_i(i) { cout << " 构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
A(const A& a) : m_i(a.m_i) { cout << " 拷贝构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
~A() { cout << " 析构函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
int m_i;
};
void myPrint(unique_ptr<int> pzn) //pzn的地址就是main中的myp的地址
{ }
int main()
{
unique_ptr<int> myp(new int(100));
//thread myThread(myPrint, myp); //unique_ptr(独享):myPrint中拷贝myp到临时变量
thread myThread(myPrint, std::move(myp)); //ok,函数myPrint结束时,pzn(即原来myp指向的地址)被释放
myThread.join();
//myThread.detach(); //err,myp可能在 move() 之前就被释放了?
cout << " mainthread " << endl;
return 0;
}
/*使用类成员函数地址指针作为线程的入口函数*/
class A {
public:
int m_i;
A(int i) : m_i(i) { cout << " 构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
A(const A& a) : m_i(a.m_i) { cout << " 拷贝构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
~A() { cout << " 析构函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
void thread_work(int num) {
cout << " subthread: " << this << " threadId= " << std::this_thread::get_id() << endl;
}
};
int main()
{
A myobj(10);
//std::thread myThread(&A::thread_work, std::ref(myobj), 15); //err,引用,detach() 会内存泄漏(myobj提前被销毁)
//std::thread myThread(&A::thread_work, &myobj, 15); //与上行等价
std::thread myThread(&A::thread_work, myobj, 15); //线程入口函数(传入地址?)、对象名、入口函数的参数,也可以detach()(在主线程中拷贝对象)
myThread.join();
//myThread.detach();
return 0;
}
/*用类中 operator() 作为线程的入口*/
class A {
public:
int m_i;
A(int i) : m_i(i) { cout << " 构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; } //类型转换构造函数:将int 变量转为类A的对象
A(const A& a) : m_i(a.m_i) { cout << " 拷贝构造函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
~A() { cout << " 析构函数执行 " << this << " threadId= " << this_thread::get_id() << endl; }
void operator() (int num) {
cout << " operator() subthread: " << this << " threadId= " << std::this_thread::get_id() << endl;
}
};
void myPrint(unique_ptr<int> pzn)
{ }
int main()
{
A myobj(10);
std::thread myThread(myobj, 15);//在主线程中调用拷贝构造,detach()安全
//std::thread myThread(std::ref(myobj), 15);//引用,不可以用detach()
//std::thread myThread(&myobj, 15); //无此用法
myThread.join();
//myThread.detach();
return 0;
}
第四节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
using namespace std;
/*借助vector管理 thread:便于一次创建大量的线程并进行管理*/
void myPrint(int inum)
{
cout << "myprint线程开始执行了,线程编号=" << inum << endl;
}
int main() //可发现线程调度是乱的(顺序和操作系统的线程运行调度机制有关)
{
vector <thread> myThreads;
for (int i = 0; i < 10; i++)
{
myThreads.push_back(thread(myPrint, i)); //创建线程并开始运行
}
for (auto iter = myThreads.begin(); iter != myThreads.end(); ++iter)
{
iter->join(); //等待10个线程都返回
}
cout << " mainthread " << endl;
return 0;
}
/*多个线程中读写同一数据,有时会相互冲突;当所有线程只读数据,则数据资源本身不会混乱,可不加互斥量,但输出会无序,对输出顺序有要求的话,仍要加*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
List.push_back(i);
}
}
void outClass()
{
for (int i = 0; i < 1000000; i++)
{
if (!List.empty())
{
int command = List.front();//读取第一个元素
List.pop_front(); //移除第一个元素
}
else
{
cout << " *****outClass()执行,但目前消息队列中为空***** " << i << endl;
}
}
}
private:
list<int> List;
};
int main()
{
A a;
thread outObj(&A::outClass, std::ref(a)); //引用对象,要 join() 等待
thread inObj(&A::inClass, std::ref(a)); //两个线程对数据的读写相互冲突
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
第五节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
/*互斥量mutex(类名):给共享数据加锁,让其他想使用共享数据的线程在自己的lock()处阻塞至解锁;
lock()数量越少、锁住的代码量越少(锁的粒度越细度),程序运行效率越高;
同时运行到多个线程的lock(),先执行哪一个由操作系统决定,所以各个lock()的运行次数不同*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << " List.size(): " << List.size() << endl;
Mutex.lock();
List.push_back(i); //在 lock() 、 unlock() 之间使用共享数据
Mutex.unlock();
}
}
bool out(int& command)
{
Mutex.lock();
if (!List.empty())
{
command = List.front();
List.pop_front();
Mutex.unlock(); //保证lock()、unlock()一一对应
return true;
}
Mutex.unlock(); //保证lock()、unlock()一一对应
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
if (out(command) == true)
{
cout << " outClass执行,剔除首元素: " << command << endl;
}
else
{
cout << " *****outClass执行,但目前消息队列为空***** " << i << endl;
}
}
}
private:
list<int> List; //共享的数据
mutex Mutex; //创建互斥量对象
};
int main()
{
A a;
thread outObj(&A::outClass, std::ref(a)); //std::thread outObj = std::thread(&A::outClass, std::ref(a));
thread inObj(&A::inClass, std::ref(a));
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/*std:lock_guard(类模板,免去手动 unlock(),且更安全):lock_guard构造函数中执行了mutex::lock(),退出作用域后析构执行mutex::unlock()*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
{ cout << " inClassA()开始执行,插入元素: " << i << endl;
//Mutex.lock();
lock_guard <std::mutex> lockguard(Mutex);
List.push_back(i);
//Mutex.unlock(); //更容易控制解锁位置
}//如果for() 内有大量其他代码,可用括号提前结束 lock_guard以提前解锁
//...其他代码....
}
}
bool out(int& command)
{
lock_guard <std::mutex> lockguard(Mutex);
//Mutex.lock();
if (!List.empty())
{
command = List.front();
List.pop_front();
//Mutex.unlock();
return true;
}
//Mutex.unlock();
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex;
};
int main()
{
A a;
thread outObj(&A::outClass, std::ref(a));
thread inObj(&A::inClass, std::ref(a));
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/*死锁:多个线程在锁多个互斥量锁头时产生冲突而卡住
线程A:先锁金锁,再锁银锁;设此时A已经锁住金锁,等待银锁解锁后锁银锁;线程A拿不到银锁头就不会放开金锁头
线程B:先锁银锁,再锁金锁;设此时B已经锁住银锁,等待金锁解锁后锁金锁;线程B拿不到金锁头就不会放开银锁头
两个线程各卡在自己内部第二个锁头处
解决办法:各个线程的锁头顺序一致*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
// lock_guard <std::mutex> sbguard1(Mutex1); //用 lock_guard 效果一样
// lock_guard <std::mutex> sbguard2(Mutex2);
Mutex1.lock();
//...两个lock()中间可有其他代码
Mutex2.lock();
List.push_back(i);
Mutex2.unlock(); //解锁顺序任意
Mutex1.unlock();
}
}
bool out(int& command)
{
Mutex2.lock();
Mutex1.lock(); //锁头顺序和上面相反
//...
// lock_guard <std::mutex> sbguard1(Mutex2);
// lock_guard <std::mutex> sbguard2(Mutex1);//锁头顺序和上面相反
if (!List.empty())
{
command = List.front();
List.pop_front();
Mutex1.unlock(); //解锁顺序任意
Mutex2.unlock();
return true;
}
Mutex1.unlock();
Mutex2.unlock();
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取 出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1; //一个互斥量拥有一个锁头
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/*std::lock()函数模板(避免死锁):一次性锁住多个互斥量(一个互斥量就不能调用此模板),使所有互斥量同为锁住、解锁状态;
std::lock()锁定互斥量过程中,如果没成功锁住所有互斥量,则把已经锁住的解锁(允许其他线程调用,以避免死锁发生),程序卡住直到所有互斥量都可以锁住
(std::lock()其实很少用:因为每个互斥量保护着不同的数据段) */
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::lock(Mutex1, Mutex2); //可写更多的互斥量
//std::lock_guard<std::mutex> sbguard1(Mutex1, std::adopt_lock); //adopt_lock:在lock_guard()之前已经获得了锁,无需再次上锁;但是解锁操作交由lock_guard对象sbguard1管理,在sbguard1的生命周期结束后,Mutex1对象会自动解锁
//std::lock_guard<std::mutex> sbguard2(Mutex2, std::adopt_lock); //使用结构体对象adopt_lock前要 lock() mutex对象,告知lock_guard不用再lock()了
List.push_back(i);
Mutex2.unlock();
Mutex1.unlock(); //顺序任意
}
}
bool out(int& command)
{
std::lock(Mutex1, Mutex2);
//std::lock_guard<std::mutex> sbguard1(Mutex1, std::adopt_lock);
//std::lock_guard<std::mutex> sbguard2(Mutex2, std::adopt_lock);
if (!List.empty())
{
command = List.front();
List.pop_front();
Mutex1.unlock();
Mutex2.unlock();
return true;
}
Mutex1.unlock();
Mutex2.unlock();
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
第六讲
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
/* unique_lock 类模板效果等价于 lock_guard,但更灵活:允许手动锁定和解锁,且可以多次锁定和解锁;但: 效率低,内存占用多
unique_lock 对象以独占所有权的方式管理 mutex 对象的上锁和解锁操作(没有其他的 unique_lock 对象同时拥有 mutex 对象的所有权)
unique_lock 对象同样也不负责管理 Mutex 对象的生命周期,在某个 unique_lock 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 unique_lock 的生命周期结束之后,它所管理的锁对象会被解锁,和 lock_guard 类似
也有adopt_lock用法 std::unique_lock<std::mutex> sbguard1(Mutex1, std::adopt_lock);
std::lock_guard没有提供延迟锁定或超时锁定的功能。它会立即尝试锁定互斥量,如果无法锁定,则会阻塞直到成功为止。
std::unique_lock可以选择延迟锁定互斥量,也可以设置超时时间,在一段时间内尝试锁定互斥量,如果超时仍未成功锁定,则可以执行其他操作。*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::lock_guard<std::mutex> sbguard1(Mutex1);
// std::unique_lock<std::mutex> sbguard1(Mutex1);
List.push_back(i);
}
}
bool out(int& command)
{
std::lock_guard<std::mutex> sbguard1(Mutex1);
// std::unique_lock<std::mutex> sbguard1(Mutex1);
std::chrono::milliseconds dura(1000);
std::this_thread::sleep_for(dura); //此处延时 1s,因为此行在lock()作用域,所以其他线程被动等待5s
//std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //std::this_thread::sleep_for(chrono::seconds(5));
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/* std::try_to_lock :unique_lock尝试锁定mutex对象,但是如果没锁住,跳出unique_lock并继续执行*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::unique_lock<std::mutex> sbguard1(Mutex1, std::try_to_lock); //在unique_lock()内部调用lock()上锁
if (sbguard1.owns_lock()) //成功拿到了锁
{
List.push_back(i);
}
else
{ //在 outClass() 中延迟了5s,所以5s内 inClass() 拿不到锁,又因为使用了 try_to_lock ,所以inClass() 线程任会继续执行
cout << " inClass()执行,但是没有拿到锁 " << i << endl;
}
List.push_back(i);
}
}
bool out(int& command)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/* unique_lock的 defer_lock:初始化没有加锁的mutex(之后加锁),在lock()后可临时解锁并处理非共享数据
可无unlock(): unique_lock 会判断此处有没有 unlock(),如果没有则内部进行 unlock()*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::unique_lock<std::mutex> sbguard1(Mutex1, std::defer_lock); //将sbguard1与Mutex1(未被加锁)绑在一起
sbguard1.lock();
//...lock()、unlock() 内处理共享数据
sbguard1.unlock(); //临时解锁处理非共享数据
//...
sbguard1.lock();
//...继续处理共享数据
List.push_back(i);
sbguard1.unlock();
}
}
bool out(int& command)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/*unique_lock成员函数try_lock():尝试给互斥量加锁,拿到锁(锁住):返回true;拿不到锁:返回false;类似try_to_lock()不阻塞*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::unique_lock<std::mutex> sbguard1(Mutex1, std::defer_lock); //defer_lock不加锁
if (sbguard1.try_lock() == true) //try_lock() 尝试加锁
{
List.push_back(i);
}
else
{
cout << " inClass()执行,但没有拿到锁 " << i << endl;
}
}
}
bool out(int& command)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/* release():返回mutex对象地址指针,并释放所有权(将 unique_lock 和 mutex解绑);
如果此时mutex已被加锁,则要手动解锁*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::unique_lock<std::mutex> sbguard1(Mutex1); //将 unique_lock 和Mutex1 绑定(两个地址一样),并对Mutex1加锁
std::mutex* ptx = sbguard1.release(); //将 unique_lock 和Mutex1 解绑(sbguard1=Null),ptx接管Mutex1(ptx指向Mutex1的地址),
List.push_back(i);
ptx->unlock(); //手动解锁,因为unique_lock 和Mutex1 解绑了就不会自动解锁了
}
}
bool out(int& command)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/* std::move() : 传递unique_lock所有权(所有权可以转移,但不能复制)*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::unique_lock<std::mutex> sbguard1(Mutex1); //sbguard1拥有Mutex1的所有权
//std::unique_lock<std::mutex> sbguard2(sbguard1); //err
std::unique_lock<std::mutex> sbguard2(std::move(sbguard1));//移动语义:sbguard2和Mutex1绑定,sbguard1=NULL
List.push_back(i);
}
}
bool out(int& command)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/*return转移所有权:返回局部的unique_lock()对象*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
std::unique_lock<std::mutex> sbguard1 = rtn_unique_lock(); //将Mutex1的所有权转移给sbguard1,能自动解锁
List.push_back(i);
}
}
bool out(int& command)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
if (!List.empty())
{
command = List.front();
List.pop_front();
return true;
}
return false;
}
void outClass()
{
int command = 0;
for (int i = 0; i < 1000000; i++)
{
bool result = out(command);
if (result == true)
{
cout << " bool out()执行,取出元素: " << command << endl;
}
else
{
cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
}
}
}
std::unique_lock<std::mutex> rtn_unique_lock()
{
std::unique_lock<std::mutex> tmpguard(Mutex1);
return tmpguard; //返回函数的局部unique_lock对象(返回局部对象都会生成临时的对象,并调用移动构造函数)
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a);
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
第七讲:“设计模式” :指代码的写法跟常规写法不怎么一样,可读性不强,但程序灵活,方便维护。书《head first》
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<mutex>
using namespace std;
///*单例设计模式设计技巧*/
//std::mutex Mutex;
//
//class ChairMan
//{
//private:
// ChairMan()
// {
// cout << "ChairMan" << endl;
// }
//public:
// static ChairMan* getInstance() //静态成员变量只能由静态成员函数调用
// {
// if (singleMan == NULL) { //保证类ChairMan对象只有一个
// singleMan = new ChairMan(); //new 需要 delete
// static insightClass c1; //static:main结束时释放(执行对象析构),间接实现对象singleMan的释放(insightClass析构中有delete singleMan)
// }
// return singleMan;
// }
// class insightClass //借助嵌套类释放静态对象singleMan
// {
// public:
// ~insightClass()
// {
// if (ChairMan::singleMan)
// {
// delete ChairMan::singleMan;
// ChairMan::singleMan = NULL; //?
// }
// }
// };
// void func() {
// cout << " test " << endl;
// }
//private:
// static ChairMan* singleMan; //所有对象共享同一个静态成员变量内存空间
//};
//
//ChairMan* ChairMan::singleMan = NULL; //静态成员变量在类中声明,类外定义和初始化
//
//int main() {
//
// ChairMan* man = ChairMan::getInstance();
// ChairMan* man2 = ChairMan::getInstance(); //两个对象指向同一地址
//
// system("pause");
// return EXIT_SUCCESS;
//}
///*在多个线程中创建单例类的对象:
// 建议在主线程中且在创建所有线程前创建好单例对象和调用单例类的成员函数,并在接下来不对对象写数据(之后视为只读),
// 则在后面所有的线程中都能安全的调用类对象创建函数getInstance,并随时访问类对象中的数据;
// 但是在要求多个子线程中创建单例类对象时(主线程中没创建过),各线程中的 if (singleMan == NULL) { } 则需要互斥 */
//std::mutex Mutex;
//
//class ChairMan
//{
//private:
// ChairMan()
// {
// cout << "ChairMan" << endl;
// }
//public:
// static ChairMan* getInstance()
// {
// std::unique_lock<std::mutex> myMutex(Mutex); //加锁互斥:只允许一个线程执行new
// if (singleMan == NULL)
// { //当类对象还未被创建,且一个线程已经进入if但还未new,其他线程仍然可以进入if,所以要加锁互斥
// singleMan = new ChairMan();
// static insightClass c1;
// }
//
// return singleMan;
// }
// class insightClass
// {
// public:
// ~insightClass()
// {
// if (ChairMan::singleMan)
// {
// delete ChairMan::singleMan;
// ChairMan::singleMan = NULL;
// }
// }
// };
// void func() {
// cout << " test " << endl;
// }
//private:
// static ChairMan* singleMan;
//};
//
//ChairMan* ChairMan::singleMan = NULL;
//
//void mythread() {
// cout << " subThread begin" << endl;
// ChairMan* man = ChairMan::getInstance();
// cout << " subThread end " << endl;
// return;
//}
//
//int main() {
//
// std::thread a1(mythread);
// std::thread a2(mythread);
// a1.join();
// a2.join();
//
// system("pause");
// return EXIT_SUCCESS;
//}
///*上面每次调用getInstance()创建对象时都会取锁,然而互斥锁只有在单例对象还未创建时才有意义,因此效率不高*/
//std::mutex Mutex;
//
//class ChairMan
//{
//private:
// ChairMan()
// {
// cout << "ChairMan" << endl;
// }
//public:
// static ChairMan* getInstance()
// {
// if (singleMan == NULL) {
// std::unique_lock<std::mutex> myMutex(Mutex); //若单例类对象已经存在,线程就不再加锁
// if (singleMan == NULL) {
// singleMan = new ChairMan();
// static insightClass c1;
// }
// }
// return singleMan;
// }
// class insightClass
// {
// public:
// ~insightClass()
// {
// if (ChairMan::singleMan)
// {
// delete ChairMan::singleMan;
// ChairMan::singleMan = NULL;
// }
// }
// };
// void func() {
// cout << " test " << endl;
// }
//private:
// static ChairMan* singleMan;
//};
//
//ChairMan* ChairMan::singleMan = NULL;
//
//void mythread() {
// cout << " subThread begin" << endl;
// ChairMan* man = ChairMan::getInstance();
// cout << " subThread end " << endl;
// return;
//}
//
//int main() {
//
// std::thread a1(mythread);
// std::thread a2(mythread);
// a1.join();
// a2.join();
//
// system("pause");
// return EXIT_SUCCESS;
//}
///*call_once(<函数名>, <函数参数>):保证函数只被调用一次(不再需要互斥量),比互斥量更高效;
// 调用call_once()后, std::once_flag自动置位(表示call_once为已调用状态),以后再次调用call_once()也不再执行对应的函数*/
//
//std::once_flag flag;
//
//class ChairMan
//{
// static void CreateInstance() { //只被调用一次
// std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// cout << " CreateInstance() 执行 " << endl;
//
// singleMan = new ChairMan();
// static insightClass c1;
// }
//private:
// ChairMan()
// {
// cout << "ChairMan" << endl;
// }
//public:
// static ChairMan* getInstance()
// {
// std::call_once(flag, CreateInstance); //保证 CreateInstance() 只执行一次;当多个线程同时到此,其他线程要等先到达的线程执行完函数
// //在第一个线程延时20s内,可发现其他线程没有向下执行cout(阻塞在call_once处直到第一个线程执行CreateInstance结束)
// cout << " call_once() 执行结束 " << endl;
// return singleMan;
// }
// class insightClass
// {
// public:
// ~insightClass()
// {
// if (ChairMan::singleMan)
// {
// delete ChairMan::singleMan;
// ChairMan::singleMan = NULL;
// }
// }
// };
// void func() {
// cout << " test " << endl;
// }
//private:
// static ChairMan* singleMan;
//};
//
//ChairMan* ChairMan::singleMan = NULL;
//
//void mythread() {
// cout << " subThread begin " << endl;
// ChairMan* man = ChairMan::getInstance();
// man->func();
// cout << " subThread end " << endl;
// return;
//}
//
//int main() {
//
// std::thread a1(mythread);
// std::thread a2(mythread);
// a1.join();
// a2.join();
//
// system("pause");
// return 0;
//}
第八讲
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
#include <condition_variable>
using namespace std;
/*condition_variable类(条件变量:与条件相关,等待条件达成);condition_variable有成员函数wait()
wait(<>, <false/true>):false(无第二个参数则默认为false),阻塞等待被唤醒;true:跳过wait()继续向下执行
流程:
1、线程A执行到wait() (wait前已加锁)
2、wait()解锁、等待被唤醒(第二个参数为false)
3、其他线程执行到 .notify_one(),唤醒wait() (若没有其他线程在等待wait()唤醒,那么notify_one()没有任何效果)
4、wait()重新加锁(加锁前其他线程已经解锁,且这里想加锁和其他线程锁同样存在时间上竞争关系,因此wait()、notify_one()不一定交错轮流运行)
5、跳出wait()(参数要为true,且加锁成功;唤醒后,如果仍为false,则又休眠)*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
cout << " inClassA()开始执行,插入元素: " << i << endl;
//写在unique_lock上面,一般能保证inCalss的unique_lock在outClass的unique_lock之后执行(为了方便查看condition_variable如何运作的)
std::unique_lock<std::mutex> sbguard1 = rtn_unique_lock();
List.push_back(i); //调试发现这里积压了很多数据,可考虑此处限流、开更多线程等方式来pop_font()数据
conditionVariable.notify_one();
}
}
void outClass()
{
int command = 0;
while (true)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
conditionVariable.wait(sbguard1, [this]{
if (!List.empty())
return true;
return false;
});
command = List.front(); //可发现List中已有许多数据:wait()、notify_one()不一定交错轮流运行
List.pop_front();
sbguard1.unlock();
cout << " outClass()执行,取出一个元素 " << endl;
}
}
std::unique_lock<std::mutex> rtn_unique_lock()
{
std::unique_lock<std::mutex> tmpguard(Mutex1);
return tmpguard;
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
std::condition_variable conditionVariable; //条件变量类的对象
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread inObj(&A::inClass, &a); //一般先写的线程先开始执行,但也存在硬件运行等原因导致顺序不确定
inObj.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
/*当有多个线程在wait()时,notify_one()只能唤醒一个
notify_all() :可同时唤醒多个wait(),但只能有一个wait()可再次拿到锁,其他还是卡在那等待拿锁*/
class A {
public:
void inClass()
{
for (int i = 0; i < 1000000; i++)
{
std::unique_lock<std::mutex> sbguard1 = rtn_unique_lock();
cout << " inClassA()开始执行,插入元素: " << i << endl;
List.push_back(i);
conditionVariable.notify_one();
}
}
void outClass()
{
int command = 0;
while (true)
{
std::unique_lock<std::mutex> sbguard1(Mutex1);
conditionVariable.wait(sbguard1, [this] {
if (!List.empty())
return true;
return false;
});
command = List.front();
List.pop_front();
cout << " threadId = " << std::this_thread::get_id() << endl; //可发现,每次唤醒的线程wait()不一样且无序
sbguard1.unlock();
}
}
std::unique_lock<std::mutex> rtn_unique_lock()
{
std::unique_lock<std::mutex> tmpguard(Mutex1);
return tmpguard;
}
private:
list<int> List;
mutex Mutex1;
mutex Mutex2;
condition_variable conditionVariable;
};
int main()
{
A a;
thread outObj(&A::outClass, &a);
thread outObj2(&A::outClass, &a); //一个入口函数可由多个线程调用
thread inObj(&A::inClass, &a);
inObj.join();
outObj2.join();
outObj.join();
cout << " mainthread " << endl;
return 0;
}
第九节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
#include<future>
using namespace std;
/*(来自第11节)
std::async()、std::thread()区别:
std::thread():叫创建线程;系统资源紧张时(创建的线程太多),不能成功创建线程,导致系统崩溃;想取出入口函数的返回值很不方便
std::async():叫创建异步任务(区别是有时不创建子线程);系统资源紧张时,如果用async强制创建线程,系统会崩溃;可以用get()拿到返回值
std::async(std::launch::deferred | std::launch::async, <>) :为std::async()默认调用参数,由系统决定运行两个中的哪一个;
async:系统强制创建线程,系统会崩溃;
deferred:系统资源紧张时,直到get()、wait()时在主线程运行入口函数;
资源紧张:线程数量不宜超过100-200*/
/*想要线程入口函数能够返回一个结果:函数模板std::async启动一个异步任务,并返回一个类模板std::future的对象,
然后将子线程的返回结果(线程入口函数的return值)放在std::future的成员函数get()中,
要用wait()、get()收尾,虽然不写也能运行,但是不写总感觉不安全
启动异步任务:自动创建一个线程并开始执行对应的线程入口函数,返回一个std::future对象 */
int mythread() {
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000)); //延时5s
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return 5; //和std::future绑定的一定要有返回值,不然将永远卡在get()
}
int main()
{
cout << "mainthreadid =" << std::this_thread::get_id() << endl;
std::future<int> result = std::async(mythread); //<int>:所取的返回值类型,std::async创建子线程并开始执行
cout << result.get() << endl; //阻塞,直到mythread()执行完并将其返回值传给get()
//cout << result.get() << endl; //err,get()只能调用一次:future的get()使用的是移动语义,用一次就清空
//result.wait(); //阻塞,直到mythread()执行完毕,但不存放return值
return 0;
}
/*使用类的成员函数作为std::async()线程入口函数,与上面使用方法没区别*/
class A
{
public:
int mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return 5;
}
};
int main()
{
A a;
int tmppar = 12;
cout << "mainthreadid =" << std::this_thread::get_id() << endl;
std::future<int> result = std::async(&A::mythread, &a, tmppar);
cout << result.get() << endl;
return 0;
}
/* 枚举类型std::launnch:
1、std::launch::deferred :(延迟创建线程)直到std:future对象调用wait()、get()处再调用线程入口函数
(没有创建子线程,是在主线程中调用的线程入口函数;如果没有get、wait,则永远不会加载入口函数)
2、std::launch::async :在调用async函数的时候就强制创建并执行线程;
3、std::launch::deferred | std::launch::async :为std::async()默认调用的参数,由系统决定运行两个中的哪一个*/
class A
{
public:
std::string mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return "mythread() return";
}
};
int main()
{
A a;
int tmppar = 12;
cout << "mainthreadid =" << std::this_thread::get_id() << endl;
std::future<std::string> result = std::async(std::launch::deferred, &A::mythread, &a, tmppar);
// std::future<std::string> result = std::async(std::launch::async, &A::mythread, &a, tmppar);
//std::future<std::string> result = std::async(std::launch::deferred | std::launch::async, &A::mythread, &a, tmppar);
cout << "test" << endl;
cout << "test" << endl;
cout << "test" << endl;
cout << "test" << endl;
cout << result.get() << endl;
cout << "test" << endl;
cout << "test" << endl;
return 0;
}
/*类模板std::packaged_task:(打包任务:把可调用对象包装起来,并作为线程线程入口函数供调用)其模板参数是各种可调用对象 */
int mythread(int mypar) {
cout << mypar << endl;
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main()
{
cout << "mainthreadid = " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)> packagedtask(mythread); //<int(int)>:<返回值类型(函数参数类型)>;我们把函数mythread通过packaged_task包装起来
std::thread t1(std::ref(packagedtask), 1); // 创建线程并开始执行;第二个参数:线程入口函数的参数
t1.join();
std::future<int> result = packagedtask.get_future(); //std::future对象里包含有线程入口函数的返回结果,这里result保存mythread
cout << result.get() << endl; //因为join()处,子线程已经返回,所以这里不会有任何等待
cout << "I Love China!" << endl;
return 0;
}
/*类模板std::packaged_task包装lambda表达式 */
int main()
{
cout << "mainthreadid = " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)> packagedtask([](int mypar){
cout << mypar << endl;
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return 5;
});
/**/
std::thread t1(std::ref(packagedtask), 1); //创建线程并开始执行
t1.join();
std::future<int> result = packagedtask.get_future();
cout << result.get() << endl;
cout << "I Love China!" << endl;
/**/
///**/
packaged_task包装起来的可调用对象可以直接调用,所以从这个角度来讲,pakcaged_task对象,也是一个可调用对象
//packagedtask(10); //直接调用,等价于函数调用(没有创建线程)
//std::future<int> result = packagedtask.get_future();
//cout << result.get() << endl;
///**/
return 0;
}
/**/
vector <std::packaged_task<int(int)>> packagedVector;
int main()
{
cout << "mainthreadid = " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)> packagedtask([](int mypar){
cout << mypar << endl;
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return 5;
});
packagedVector.push_back(std::move(packagedtask)); //必须用移动,赋值会报错;packagedtask=empty
std::packaged_task<int(int)> packagedtask2;
auto iter = packagedVector.begin(); //就是移动packagedtask
packagedtask2 = std::move(*iter); //iter=empty,packagedVector.size()=1
packagedVector.erase(iter); //删除迭代器iter指向的元素,packagedVector.size()=0
packagedtask2(10); //调用packaged_task
std::future<int> result = packagedtask2.get_future();
cout << result.get() << endl;
return 0;
}
/*类模板std::promise:在某个线程中通过promise保存一个值,并在其他线程中把future绑定到这个promise上来得到取出之前在线程中保存的值*/
void mythread(std::promise<int>& tmppromise, int calculate) { //<int>线程给回值的类型
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
int result = calculate;
tmppromise.set_value(result); //保存值到tmp对象中
}
void mythread2(std::future<int>& tmpfuture){
auto result = tmpfuture.get();
cout << "mythread2 result" << result << endl;
}
int main() {
std::promise<int> mypromise; //声明std::promise对象mypromise,保存的值类型为int
std::thread t1(mythread, std::ref(mypromise), 10); //创建线程并开始执行
t1.join(); //用thread对象,就一定要有 join()、detach()
std::future<int> future = mypromise.get_future(); //promise和future绑定,用于获取线程返回值
auto result = future.get(); //阻塞直到获得返回值
cout << "result = " << result << endl;
std::thread t2(mythread2, std::ref(result));
t2.join();
return 0;
}
第十节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
#include<future>
using namespace std;
int mythread() {
cout << "mythread() start;" << " threadid = " << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
cout << "mythread() end;" << " threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main()
{
cout << "mainthreadid =" << std::this_thread::get_id() << endl;
//std::future<int> result = std::async(mythread);
std::future<int> result = std::async(std::launch::deferred, mythread); //deferred:实际没有创建线程,入口函数在主线程中执行
//枚举类型 std::future_status
std::future_status status = result.wait_for(1s); //等待1s;//进入源代码: s ,可发现许多时间调用方法:min,us,...;result.wait_for(std::chrono::seconds(1))
if (status == std::future_status::timeout){ //超时:希望在上面等待的1s内线程入口函数已经返回,没返回则status=timeout(表示到此行时子线程还没执行完)
cout << "超时,线程还没有执行完毕" << endl;
cout << result.get() << 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; //超时,则尽量用get()等待一下,虽然调试发现不影响,但是不加感觉不安全
}
return 0;
}
/*std::future:get()函数为转移语义,只能使用一次
std::shared_future: 也是类模板,get()函数为复制数据,可多次调用 */
int mythread(int tmp) {
cout << " mythread2() start; " << "threadid" << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
return 5;
}
void mythread2(std::shared_future<int>& tmpfuture){
cout << " mythread2() start; " << "threadid" << std::this_thread::get_id() << endl;
auto result = tmpfuture.get(); //tmpfuture=empty,可以get()许多次
cout << "mythread2 result" << result << endl;
return;
}
int main()
{
cout << "mainthreadid = " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)> packagedtask(mythread);
std::thread t1(std::ref(packagedtask), 1);
t1.join();
std::future<int> result = packagedtask.get_future();
bool ifcanget = result.valid(); //result.valid():result不为empty则有效,返回true
std::shared_future<int> result_s(result.share()); //result=empty
//std::shared_future<int> result_s(std::move(result)); //与上行等价
ifcanget = result.valid(); //empty, ifcanget=false
//std::shared_future<int> result_s(mypt.get_future(): //通过get_future返回值直接构造了shared_future对象,与上几行等价
auto mythreadresult = result_s.get();
mythreadresult = result_s.get(); //可get()多次
std::thread t2(mythread2, std::ref(result_s));
t2.join();
return 0;
}
/*C中一条语句为汇编中多条执行语句,为了C中一条语句在写入数据过程中不被其他线程打断,相互间需要加锁*/
int num = 0;
void mythread() {
for (int i = 0; i < 10000000; i++)
num++; //实际是多条汇编语句
}
int main() {
thread mythread1(mythread);
thread mythread2(mythread);
mythread1.join();
mythread2.join();
cout << "两个线程执行完毕,num=" << num << endl; //每次结果不同
}
/*类模板std::atomic原子操作:不再用互斥量加锁保护数据的多线程并发编程方式,用来封装某个类型的值,确保任意时刻只有一个线程访问共享数据
原子指“不可分割的操作”,即操作状态只有完成、未完成状态
一般都只针对一个变量,而不是像互斥量一样为代码片段,但由于原子操作更加接近底层,因而效率更高
一般用于计数或者统计(累计发送出去了多少个数据包,累计接收到了多少个数据包)*/
std::atomic<int> num = 0; //封装int型对象(值):原子操作的实现跟无atomic的普通数据类型类似
void mythread() {
for (int i = 0; i < 10000000; i++){
num++; //此处为原子操作:执行此行过程中不会被其他线程打断
}
}
int main() {
thread mythread1(mythread);
thread mythread2(mythread);
mythread1.join();
mythread2.join();
cout << "两个线程执行完毕,num=" << num << endl; //每次结果不同
}
/*其他类型的原子操作*/
std::atomic<bool> atomicFlag = false; //线程退出标志
void mythread() {
while(atomicFlag == false) {
cout << "正在执行:threadid =" << std::this_thread::get_id() << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
cout << "运行结束:threadid = " << std::this_thread::get_id() << endl;
return;
}
int main() {
thread mythread1(mythread);
thread mythread2(mythread);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
atomicFlag = true;
mythread1.join();
mythread2.join();
return 0;
}
第11节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
#include<future>
using namespace std;
/*atomic原子操作,只支持某些操作:++, --, +=, &=,5, =, */
std::atomic<int> num = 0;
void mythread() {
for (int i = 0; i < 10000000; i++)
num = num + 1; //不支持原子操作
}
int main() {
thread mythread1(mythread);
thread mythread2(mythread);
mythread1.join();
mythread2.join();
cout << "两个线程执行完毕,num=" << num << endl;
}
第12节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
#include<future>
#include<windows.h>
using namespace std;
///*windows临界区:C++11多线程是以windows下的实现机制为基础的,所以执行效果类似
// 同一线程中,可以多次进入windows中的"相同临界区变量"代表的临界区;不同线程中的临界区则相互间等待离开临界区(与lock()相同)
//: LeaveCriticalSection()、EnterCriticalSection() 调用个数要相同(进入、离开临界区的次数要相同)
//*/
//#define __WINDOWSJQ_
//
//class A {
//public:
// A() {
//#ifdef __WINDOWSJQ_
// InitializeCriticalSection(&my_winsec); //临界区需要初始化
//
//#endif // __WINDOWSJQ_
// }
// void inClass()
// {
// for (int i = 0; i < 1000000; i++)
// {
// cout << " inClassA()开始执行,插入元素: " << i << endl;
//#ifdef __WINDOWSJQ_
// EnterCriticalSection(&my_winsec); //进入临界区(加锁),相当于 Mutex.lock();
// EnterCriticalSection(&my_winsec); //允许多次进入
// List.push_back(i); // 除了 lock()、unlock()部分其他都相同
// LeaveCriticalSection(&my_winsec); //离开临界区(解锁),相当于 Mutex.unlock();
// LeaveCriticalSection(&my_winsec); //进入、离开次数相同
//#else
// Mutex.lock();
// //Mutex.lock(); //err,不能多次加锁;lock_guard()也不可多次
// List.push_back(i);
// Mutex.unlock();
// //Mutex.unlock();
//#endif
// }
// }
// bool out(int& command)
// {
//#ifdef __WINDOWSJQ_
// EnterCriticalSection(&my_winsec);
// if (!List.empty())
// {
// command = List.front();
// List.pop_front();
// LeaveCriticalSection(&my_winsec);
// return true;
// }
// LeaveCriticalSection(&my_winsec);
//#else
// Mutex.lock();
// if (!List.empty())
// {
// command = List.front();
// List.pop_front();
// Mutex.unlock();
// return true;
// }
// Mutex.unlock();
//#endif
// return false;
// }
// void outClass()
// {
// int command = 0;
// for (int i = 0; i < 1000000; i++)
// {
// bool result = out(command);
// if (result == true)
// {
// cout << " bool out()执行,取出元素: " << command << endl;
// }
// else
// {
// cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
// }
// }
// cout << " end " << endl;
// }
//private:
// list<int> List;
// mutex Mutex;
//
//#ifdef __WINDOWSJQ_
// CRITICAL_SECTION my_winsec; //windows中的临界区,类似C++11中mutex
//#endif
//};
//int main()
//{
// A a;
// thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
//
// inObj.join();
// outObj.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
///*使用RAII类实现自动离开临界区,类似于C++11中的std::lock_guard<std::mutex>
// RAII类(Resource Acquisition is initialization):“资源获取及初始化”(容器、智能指针也是RAII类)*/
//#define __WINDOWSJQ_
//class CWinLock { //RAII类
//public:
// CWinLock(CRITICAL_SECTION* pCritmp) {
// pCritical = pCritmp;
// EnterCriticalSection(pCritical);
// }
// ~CWinLock() { //析构函数
// LeaveCriticalSection(pCritical);
// }
//private:
// CRITICAL_SECTION* pCritical; //windows中的临界区,类似C++11中mutex
//};
//
//class A {
//public:
// A() {
//#ifdef __WINDOWSJQ_
// InitializeCriticalSection(&my_winsec); //临界区需要初始化
//
//#endif
// }
// void inClass()
// {
// for (int i = 0; i < 1000000; i++)
// {
// cout << " inClassA()开始执行,插入元素: " << i << endl;
//#ifdef __WINDOWSJQ_
// CWinLock wlock(&my_winsec); //创建RAII对象 wlock
// CWinLock wlock2(&my_winsec); //可多次创建并进入
// List.push_back(i); // 除了 lock()、unlock()部分其他都相同
//#else
// Mutex.lock();
// //Mutex.lock(); //err,不能多次加锁;lock_guard()也不可多次
// List.push_back(i);
// Mutex.unlock();
// //Mutex.unlock();
//#endif
// }
// }
// bool out(int& command)
// {
//#ifdef __WINDOWSJQ_
// EnterCriticalSection(&my_winsec);
// if (!List.empty())
// {
// command = List.front();
// List.pop_front();
// LeaveCriticalSection(&my_winsec);
// return true;
// }
// LeaveCriticalSection(&my_winsec);
//#else
// Mutex.lock();
// if (!List.empty())
// {
// command = List.front();
// List.pop_front();
// Mutex.unlock();
// return true;
// }
// Mutex.unlock();
//#endif
// return false;
// }
// void outClass()
// {
// int command = 0;
// for (int i = 0; i < 1000000; i++)
// {
// bool result = out(command);
// if (result == true)
// {
// cout << " bool out()执行,取出元素: " << command << endl;
// }
// else
// {
// cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
// }
// }
// cout << " end " << endl;
// }
//private:
// list<int> List;
// mutex Mutex;
//
//#ifdef __WINDOWSJQ_
// CRITICAL_SECTION my_winsec; //windows中的临界区,类似C++11中mutex
//#endif
//};
//int main()
//{
// A a;
// thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
//
// inObj.join();
// outObj.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
///*std::mutex:独占互斥量,自己1ock时别人lock不了
// 当在其中一个入口函数中调用了另一个入口函数,调用这两个入口函数的两个线程同时运行时,同一个入口函数可能会同时被lock()两次而报错,
// 解决方式:使用递归的独占互斥量recursive_mutex(允许同一个线程中的同一个互斥量lock多次(效率比mutex低),但是尽量少用(从代码技巧上解决)
// recursive_mutex也有lock()、unlock()
// recursive_mutex递归次数(被调用次数)可以非常多,但是是有限制的
//
// 此处演示:在lock()、unlock()间多次重复加锁*/
//class A {
//public:
// void inClass() //入口函数1
// {
// for (int i = 0; i < 1000000; i++)
// {
// cout << " inClassA()开始执行,插入元素: " << i << endl;
// std::lock_guard<std::recursive_mutex> sbguard(Mutex); //第一次加锁
// fun1(); //加了3次锁
// List.push_back(i);
// }
// }
// 下面似乎没什么作用,所以注释了
// //bool out(int& command)
// //{
// // Mutex.lock();
// // if (!List.empty())
// // {
// // command = List.front();
// // List.pop_front();
// // Mutex.unlock();
// // return true;
// // }
// // Mutex.unlock();
// // return false;
// //}
// //void outClass() //入口函数2
// //{
// // int command = 0;
// // for (int i = 0; i < 1000000; i++)
// // {
// // bool result = out(command);
// // if (result == true)
// // {
// // cout << " bool out()执行,取出元素: " << command << endl;
// // }
// // else
// // {
// // cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
// // }
// // }
// // cout << " end " << endl;
// //}
// void fun1() { //第二次加锁
// std::lock_guard<std::recursive_mutex> sbguard(Mutex);
// //...
// fun2();
// }
// void fun2() { //第三次加锁
// std::lock_guard<std::recursive_mutex> sbguard(Mutex);
// //...
// }
//private:
// list<int> List;
// recursive_mutex Mutex; //递归独占互斥量recursive_mutex对象
//};
//int main()
//{
// A a;
// //thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
//
// inObj.join();
// //outObj.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
///*std::timed_mutex:带超时功能的独占互斥量
// std::timed_mutex::try_lock_for(<时间长度>):参数是一段时间;true:在等待期间达到了锁;false:等待期间没有拿到锁;等待时间结束后无论有没有拿到锁都会跳出此句
// std::timed_mutex::try_lock_until(<时刻>):参数是未来的某个时刻;在未来的某时刻前尝试拿锁;功能和try_lock_for()相同*/
//class A {
//public:
// void inClass()
// {
// for (int i = 0; i < 1000000; i++)
// {
// cout << " inClassA()开始执行,插入元素: " << i << endl;
// if (Mutex.try_lock_for(std::chrono::milliseconds(100))) { //等待100ms来尝试获取锁头
// //if (Mutex.try_lock_until(chrono::steady_clock::now() + std::chrono::milliseconds(100))) { //此刻的时间点+100ms
// //拿到锁头
// List.push_back(i);
// Mutex.unlock(); //获取了锁头就要解锁
// cout << "获取了锁头" << endl;
// }
// else { //没有拿到锁头
// cout << "没有拿到锁头" << endl;
// }
// }
// }
// bool out(int& command)
// {
// Mutex.lock();
// std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //让线程入口函数inClass()中的try_lock_for()拿不到锁
// if (!List.empty())
// {
// command = List.front();
// List.pop_front();
// Mutex.unlock();
// return true;
// }
// Mutex.unlock();
// return false;
// }
// void outClass()
// {
// int command = 0;
// for (int i = 0; i < 1000000; i++)
// {
// bool result = out(command);
// if (result == true)
// {
// cout << " bool out()执行,取出元素: " << command << endl;
// }
// else
// {
// cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
// }
// }
// cout << " end " << endl;
// }
//private:
// list<int> List;
// std::timed_mutex Mutex; //带超时功能的独占互斥量timed_mutex对象
//};
//int main()
//{
// A a;
// thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
//
// inObj.join();
// outObj.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
///*std::recursive_timed_mutex:也是 带超时功能的递归独占互斥量(允许同一个线程多次获取这个互斤量);用法与std::timed_mutex相同*/
//class A {
//public:
// void inClass()
// {
// for (int i = 0; i < 1000000; i++)
// {
// cout << " inClassA()开始执行,插入元素: " << i << endl;
// if (Mutex.try_lock_for(std::chrono::milliseconds(100))) { //1
// //if (Mutex.try_lock_until(chrono::steady_clock::now() + std::chrono::milliseconds(100))) { //2
// List.push_back(i);
// Mutex.unlock();
// cout << "获取了锁头" << endl;
// }
// else {
// cout << "没有拿到锁头" << endl;
// }
// }
// }
// bool out(int& command)
// {
// Mutex.lock();
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// if (!List.empty())
// {
// command = List.front();
// List.pop_front();
// Mutex.unlock();
// return true;
// }
// Mutex.unlock();
// return false;
// }
// void outClass()
// {
// int command = 0;
// for (int i = 0; i < 1000000; i++)
// {
// bool result = out(command);
// if (result == true)
// {
// cout << " bool out()执行,取出元素: " << command << endl;
// }
// else
// {
// cout << " bool out()执行,但目前消息队列中为空 " << i << endl;
// }
// }
// cout << " end " << endl;
// }
//private:
// list<int> List;
// std::recursive_timed_mutex Mutex; //与上段代码只有这里不同
//};
//int main()
//{
// A a;
// thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
//
// inObj.join();
// outObj.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
第13节
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
#include<future>
#include<windows.h>
using namespace std;
///*虚假唤醒:当保护的数据为空时,wait()被唤醒处理数据*/
//class A {
//public:
// void inClass()
// {
// for (int i = 0; i < 1000000; i++)
// {
// std::unique_lock<std::mutex> sbguard1 = rtn_unique_lock();
// cout << " inClassA()开始执行,插入元素: " << i << endl;
// List.push_back(i);
//
// conditionVariable.notify_one();
// //...
// //conditionVariable.notify_one();
// //conditionVariable.notify_one();
// //这里的虚假唤醒:有多个notify_one()且运行时多次唤醒wait()并处理数据,从代码段来看,很有可能导致数据为空
// }
// }
// void outClass()
// {
// int command = 0;
// while (true)
// {
// std::unique_lock<std::mutex> sbguard1(Mutex1);
// conditionVariable.wait(sbguard1, [this] {
// if (!List.empty()) //处理虚假唤醒,保证下面对数据的处理front()、pop_front()是安全的
// return true;
// return false;
// });
// command = List.front();
// List.pop_front();
// cout << " threadId = " << std::this_thread::get_id() << endl;
// sbguard1.unlock();
// }
// }
// std::unique_lock<std::mutex> rtn_unique_lock()
// {
// std::unique_lock<std::mutex> tmpguard(Mutex1);
// return tmpguard;
// }
//private:
// list<int> List;
// mutex Mutex1;
// mutex Mutex2;
// condition_variable conditionVariable;
//};
//
//int main()
//{
// A a;
//
// thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
//
// inObj.join();
// outObj.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
///*原子操作:拷贝、读、写...*/
//class A {
//public:
// atomic<int> atom;
// A() {
// atom = 0;
// //atomic<int> atom2 = atom; //err:“尝试引用已删除的函数”,因为拷贝的原子操作及其麻烦,所以编译器内部使用delete删除了拷贝构造函数
// atomic<int> atom2;
// //atom2 = atom; //err,拷贝赋值运算符已被删除
//
// atomic<int> atm2(atom.load()); //load():以原子方式读atomic对象的值
// auto atm3(atom.load());
//
// atm2 = 12; //以原子方式写入内容
// atm2.store(12); //与上行等价
// }
// void inClass()
// {
// for (int i = 0; i < 1000000; i++)
// {
// atom += 1; //原子操作
// }
// }
// void outClass()
// {
// while (true) {
// cout << atom << endl; //读atom是原子操作,然而cout<<atom不是原子操作
// }
// }
//private:
// list<int> List;
// mutex Mutex1;
// mutex Mutex2;
//};
//int main()
//{
// A a;
//
// thread outObj(&A::outClass, &a);
// thread inObj(&A::inClass, &a);
// thread inObj2(&A::inClass, &a);
//
// outObj.join();
// inObj.join();
// inObj2.join();
//
// cout << " mainthread " << endl;
// return 0;
//}
/* 如果程序运行过程中需要不断创建大量线程并用完释放销毁,会带来效率低、程序稳定性问题
线程池:把一堆线程放在一起统一管理,循环利用;用的时候拿出线程,不用的时候放回空闲(不销毁)
实现方式:在启动程序时就创建好一定数量的线程*/
/* 线程创建数量建议:
2000个线程基本就是极限,再创建线程就会崩溃
调用某些技术开发程序时:其api接口提供商会建议线程创建数量,如:=cpu数量、cpu *2、cpu*2+2
根据业务需求确定数量:一个线程等于一条执行通路
线程数量不是越多越好:(线程间的切换、保存、恢复数据占用很多时间)尽量不要超过500个,能控制在200个之内最理想(可调试测试合适数量)*/
/* C++11目前还不能满足所有多线程需求,实际中常常需要和以往的windows、linux多线程库结合使用*/
other: 获取线程ID和CPU核心数:
void func()
{
this_thread::sleep_for (chrono::seconds(1));//休眠1秒
//获取当前线程id
cout << "func id = " << this_thread::get_id() << endl;
}
int main()
{
thread t(func);
cout << "t.get_id() = " << t.get_id() << endl; //获取线程t的id
cout << "main id = "<<this_thread::get_id() << endl; //主线程id
cout << "cup num = " << thread::hardware_concurrency() << endl;//获取cpu核心数,失败返回0
t.join(); //线程阻塞
/*
运行结果:
t.get_id() = 2
main id = 1
cup num = 4
func id = 2
*/
return 0;
}