并发
多个任务(独立活动)同时发生(进行)。
单CPU,操作系统调度,任务切换。
多CPU,硬件并发(并行)。
可执行程序
Windows下exe文件,Linux下有可执行权限的文件(-rwxrw-r–)。
进程
一个可执行程序运行起来创建一个进程,进程就是运行起来了的可执行程序。
线程
每个进程有唯一主线程,随进程启动。
线程理解为一条代码的执行通路(道路)。
每个线程需要独立的堆栈空间(耗费内存,1MB左右),线程切换需保存很多中间状态。上下文切换必须但无价值和意义的额外工作,耗费资源。
多进程并发
多个可执行程序运行。同一计算机上进程通过管道、文件、消息队列、共享内存等技术通信,不同计算机间进程通过socket(网络套接字)等通信。进程直接数据保护问题,相互通信复杂(即使同一台计算机上)。
多线程并发
单个进程创建多个线程(轻量级进程,独立运行),共享进程地址空间(共享内存)、全局变量、指针、引用等。
总结
与多进程并发相比较,多线程并发的优缺点:
优点:线程轻量级,启动速度更快;系统资源开销更少;执行速度更快。
缺点:使用有难度,小心数据一致性问题。
主线程执行完后,未执行完的子线程会被操作系统强制终止(detach例外)。
#include
#include
using namespace std;
void myprint() {
cout <<"线程开始" <<endl;
cout <<"线程结束" <<endl;
}
int main() {
thread mytobj(myprint);//函数myprint是可调用对象
mytobj.join();
cout <<"main主函数结束" <<endl;
return 0;
}
线程detach后,线程关联的thread对象失去与线程的关联,线程驻留在后台运行(控制台不会输出),由C++运行时库接管(负责清理该线程相关的资源),类似守护线程。
#include
#include
using namespace std;
void myprint() {
cout <<"线程开始" <<endl;
cout <<"线程结束1" <<endl;
cout <<"线程结束2" <<endl;
cout <<"线程结束3" <<endl;
cout <<"线程结束4" <<endl;
cout <<"线程结束5" <<endl;
cout <<"线程结束6" <<endl;
cout <<"线程结束7" <<endl;
cout <<"线程结束8" <<endl;
}
int main() {
thread mytobj(myprint);//函数myprint是可调用对象
mytobj.detach(); //主线程结束后,myprint子线程转入后台执行,看不见输出结果(输出结果的窗口关联的是主线程)
cout <<"main主函数结束" <<endl;
return 0;
}
thread mytobj(myprint);
if(mytobj.joinable())
cout <<"joinable() == true" <<endl;
mytobj.join();//或者mytobj.detach();
//joinable()用于判断线程是否调用过join或者detach
if(!mytobj.joinable())
cout <<"joinable() == false" <<endl;
class TA {
public:
void operator()() {//重载(),可调用对象
cout <<"TA::operator()开始" <<endl;
cout <<"m_i: " <<m_i <<endl;
cout <<"TA::operator()结束" <<endl;
}
TA(int i):m_i(i){
cout <<"TA(int i), this=" <<this <<endl;
}
~TA() {
cout <<"~TA(), this=" <<this <<endl;
}
TA(const TA& ta):m_i(ta.m_i){
cout <<"TA(const TA& ta), this=" <<this <<endl;
}
int m_i;
//隐患
//引用值,当main线程结束时,变量myi会销毁,引用无效
//TA(int& i):m_i(i){}
//int& m_i;
};
int myi = 6;
TA ta(myi);
//ta对象会被复制到子线程,main线程销毁ta对子线程无影响。
thread mytobj(ta); //thread mytobj(TA(myi));临时对象,编译出错
//ta.join();
ta.detach();
cout <<"main结束" <<endl;
auto mylamthread = [] {
cout <<"线程开始" <<endl;
cout <<"线程结束" <<endl;
};
thread mytobj(mylamthread);
mytobj.join();//或者mytobj.detach();
//const引用会产生临时对象
void myprint(int i, const string& mybuf) {}
void myprint(int i, const string& mybuf) {}
int mvar = 1;
char mybuf[] = "test";
//mybuf转换为string时机不确定,潜在问题
thread mytobj(myprint, mvar, mybuf);
//构造string临时对象,无问题
thread mytobj(myprint, mvar, string(mybuf));
自定义类测试
#include
#include
using namespace std;
class A
{
public:
A(int a) : m_i(a) { cout << "A::A(int a)" << this << endl; }
A(const A &a) { cout << "A::A(const A& a)" << this << endl; }
~A() { cout << "~A::A()" << this << endl; }
private:
int m_i;
};
void myprint(int i, const A &mybuf)
{
cout << &mybuf << endl;
}
int main()
{
int mvar = 1;
int secondvar = 12;
// 拷贝构造函数可能未执行,main线程就结束了
//thread mytobj(myprint, mvar, secondvar);
// main线程,执行一次构造函数+一次拷贝构造函数(生成类A实例位于子线程中)+一次析构函数
// 子线程中,输出实例A地址+一次析构函数
thread mytobj(myprint, mvar, A(secondvar));
//mytobj.join();
mytobj.detach();
cout << "main over" << endl;
return 0;
}
std::this_thread::get_id()
#include
#include
using namespace std;
class A
{
public:
A(int a) : m_i(a) { cout << "A::A(int a) this: " << this <<" id: "<< this_thread::get_id() << endl; }
A(const A &a) { cout << "A::A(const A& a) this: " << this <<" id: "<< this_thread::get_id() << endl; }
~A() { cout << "~A::A() this: " << this <<" id: "<< this_thread::get_id() << endl; }
private:
int m_i;
};
void myprint2(const A &mybuf)
{
cout <<"this: "<< &mybuf <<" id: "<< this_thread::get_id() << endl;
}
//void myprint2(const A mybuf)
//非引用时,
//子线程中会增加一次拷贝构造函数+一次析构函数
int main()
{
cout << "main id: " << this_thread::get_id() << endl;
int mvar = 1;
//子线程中利用变量mvar创建A实例
//mvar可能因main执行完毕而回收,潜在问题。
//thread mytobj(myprint2, mvar);
// main线程执行构造函数和拷贝构造函数(创建两个A的实例)
// 构造函数创建的实例A执行完拷贝构造后,main线程析构
// 拷贝构造函数创建的实例A归子线程所有,且由子线程析构
thread mytobj(myprint2, A(mvar));
mytobj.join();
cout << "main over" << endl;
return 0;
}
建议
//函数使用类的常量引用
void myprint2(const A& mybuf);
//创建线程时构建临时对象
thread mytobj(myprint2, A(mvar));
临时对象不能作为非const引用参数。
#include
#include
using namespace std;
class A
{
public:
A(int a) : m_i(a) { cout << "A::A(int a) this: " << this << " id: " << this_thread::get_id() << endl; }
A(const A &a) { cout << "A::A(const A& a) this: " << this << " id: " << this_thread::get_id() << endl; }
~A() { cout << "~A::A() this: " << this << " id: " << this_thread::get_id() << endl; }
mutable int m_i; // mutable,const&可修改
};
//c++只会为const引用产生临时对象
//临时对象不能作为非const引用
void myprint2(const A &a)
{
a.m_i = 199;
}
int main()
{
A myobj(10);
//thread t(myprint2, myobj); //子线程调用拷贝构造函数生成A实例
thread t(myprint2, std::ref(myobj)); //真引用main线程的A实例
t.join();
cout << myobj.m_i << endl;
cout << "main over" << endl;
return 0;
}
#include
#include
using namespace std;
class A
{
public:
A(int a) : m_i(a) { cout << "A::A(int a) this: " << this << " id: " << this_thread::get_id() << endl; }
A(A &a) { cout << "A::A(A& a) this: " << this << " id: " << this_thread::get_id() << endl; }
~A() { cout << "~A::A() this: " << this << " id: " << this_thread::get_id() << endl; }
int m_i;
};
void myprint2(A &a)
{
a.m_i = 199;
cout << "myprint2(A &a) this: " << &a << " id: " << this_thread::get_id() << endl;
}
int main()
{
A myobj(10);
thread t(myprint2, std::ref(myobj)); //真传递引用,可修改
t.join();
cout << myobj.m_i << endl;
cout << "main over" << endl;
return 0;
}
#include
#include
using namespace std;
void myprint3(unique_ptr<int> pzn)
{
*pzn = 22;
}
int main()
{
unique_ptr<int> myp(new int(100));
cout<< *myp <<endl;
thread t(myprint3, std::move(myp));//unique_ptr转移到子线程,myp为空
cout << "myp==nullptr: "<<(myp==nullptr) <<endl;
t.join(); //必须等待,main线程创建内存空间myp,子线程在使用。
cout << "main over" << endl;
return 0;
}
#include
#include
using namespace std;
class A
{
public:
A(int a) : m_i(a) { cout << "A::A(int) this: " << this << " id: " << this_thread::get_id() << endl; }
A(A &a) { cout << "A::A(A&) this: " << this << " id: " << this_thread::get_id() << endl; }
~A() { cout << "~A::A() this: " << this << " id: " << this_thread::get_id() << endl; }
public:
void thread_work(int num)
{
cout << "this: " << this << " id: " << this_thread::get_id() << endl;
}
int m_i;
};
class A2
{
public:
A2(int a) : m_i(a) { cout << "A2::A2(int) this: " << this << " id: " << this_thread::get_id() << endl; }
A2(A2 &a) { cout << "A2::A2(A2&) this: " << this << " id: " << this_thread::get_id() << endl; }
~A2() { cout << "~A2::A2() this: " << this << " id: " << this_thread::get_id() << endl; }
public:
void operator()(int num)
{
cout << "this: " << this << " id: " << this_thread::get_id() << endl;
}
int m_i;
};
int main()
{
if(0)
{
A a(3);
thread obj(&A::thread_work, a, 15);//拷贝构造函数主线程执行,析构函数子线程执行
obj.join();
}
if(0)
{
A a(3);
thread obj(&A::thread_work, &a, 15);
//thread obj(&A::thread_work, std::ref(a), 15);//同上,无拷贝构造函数,主线程和子线程共用类a
obj.join();
}
if(0)
{
A2 a(3);
thread obj(a, 15);//拷贝构造函数主线程执行,析构函数子线程执行
obj.join();
}
if(1)
{
A2 a(3);
//thread obj(&a, 15);//error
thread obj(std::ref(a), 15);//无拷贝构造函数,主线程和子线程共用类a
obj.join();
}
cout << "over!\n";
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
void myprint(int num)
{
cout << num << endl;
}
#define N 5
int main()
{
/*
vector threads;
for (int i = 0; i < N; i++)
//threads.push_back(thread(myprint, i));
threads.emplace_back(thread(myprint, i));
*/
vector<thread> threads(N);
for (int i = 0; i < N; i++)
threads[i] = thread(myprint, i);
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
/*
for (int i = 0; i < N; i++)
threads[i].join();
*/
/*
for (auto &entry : threads)
entry.join();
*/
/*
for (auto iter = threads.begin(); iter != threads.end(); ++iter)
iter->join();
*/
cout << "main over" << endl;
return 0;
}
只读没问题,读写需加锁。
list频繁按序插入和删除数据时效率更高,vector随机插入和删除数据时效率更高。
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 1000
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
msgRecvQueue.push_back(i);
this_thread::sleep_for(chrono::seconds(3));
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
if (msgRecvQueue.empty())
{
cout<<"empty"<<endl;
}
else
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
cout<<"do something"<<endl;
}
this_thread::sleep_for(chrono::seconds(1));
}
}
private:
list<int> msgRecvQueue;
};
int main()
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
cout << "main over" << endl;
return 0;
}
互斥量,mutex,一个类,一把锁。
保护需要保护的数据。保护数据少了,无保护效果;保护数据多了,影响程序运行效率。
mutex mtx;
mtx.lock();
mtx.unlock();
mutex mtx;
std::lock_guard<mutex> guard(mtx);
都等待对方释放锁,而都锁住了对方需要的锁,相互等待。
一般解决方法是按相同顺序上锁。
m1.lock();
m2.lock();
m2.unlock();
m1.unlock();
//或者
lock_guard<mutex> g1(m1);
lock_guard<mutex> g2(m2);
lock可以一次锁住两个及以上互斥量。(要么都锁住,要么都不锁)
std::lock(m1, m2);//m1,m2先后顺序无关
m2.unlock();
m1.unlock();
mutex m1;
mutex m2;
std::lock(m1, m2);//m1,m2先后顺序无关,同时锁住m1和m2
lock_guard<mutex> g1(m1, std::adopt_lock);
lock_guard<mutex> g2(m2, std::adopt_lock);
//lock_guard g1(m1);
//g1构造函数中调用lock,析构函数调用unlock
//std::adopt_lock告诉g1构造函数中不调用lock
一般使用lock_guard。
unique_lock比lock_guard更灵活,执行效率差一点,内存占用多一点。
#include
#include
#include
#include
using namespace std;
#define N 5
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
lock_guard guard(mtx);
msgRecvQueue.push_back(i);
this_thread::sleep_for(chrono::milliseconds(30));
}
}
void outMsgRecvQueue()
{
int command;
for (int i = 0; i < N; i++)
{
bool result = outMsgLULProc(command);
if (!result)
{
cout << "empty" << endl;
}
else
{
cout << "do something" << endl;
}
this_thread::sleep_for(chrono::milliseconds(10));
}
}
private:
bool outMsgLULProc(int &command)
{
lock_guard guard(mtx);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
private:
list<int> msgRecvQueue;
mutex mtx;
};
int main()
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
cout << "main over" << endl;
return 0;
}
unique_lock可完全取代lock_guard。
mutex m;
m.lock();
unique_lock<mutex> g(m, adopt_lock);
#include
#include
#include
#include
using namespace std;
#define N 5
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
unique_lock guard(mtx, try_to_lock);//mtx不能lock
if(guard.owns_lock()) // 拿到锁头
msgRecvQueue.push_back(i);
this_thread::sleep_for(chrono::milliseconds(30));
}
}
void outMsgRecvQueue()
{
int command;
for (int i = 0; i < N; i++)
{
bool result = outMsgLULProc(command);
if (!result)
{
cout << "empty" << endl;
}
else
{
cout << "do something" << endl;
}
this_thread::sleep_for(chrono::milliseconds(10));
}
}
private:
bool outMsgLULProc(int &command)
{
unique_lock guard(mtx);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
private:
list<int> msgRecvQueue;
mutex mtx;
};
int main()
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
cout << "main over" << endl;
return 0;
}
mutex mtx;
unique_lock guard(mtx, defer_lock);//mtx不能lock
mutex mtx;
unique_lock guard(mtx, defer_lock);
guard.lock();
mutex mtx;
unique_lock guard(mtx);
guard.unlock();
mutex mtx;
unique_lock guard(mtx);
guard.try_lock();
mutex mtx;
unique_lock guard(mtx);
mutex* p_mtx = guard.release();//解除guard与mtx的关联
p_mtx->unlock();//需要自己解锁
锁住代码合适(粒度)。
unique_lock对mutex的所有权可以移动但不能复制。
mutex mtx;
unique_lock<mutex > g1(mtx);
//unique_lock g2(mtx);//error
unique_lock<mutex > g2(std::move(g1));
unique<mutex> rtn_unique_lock(){
unique_lock<mutex > g(mtx);
return g;//会生成临时对象,并调用移动构造函数
}
项目开发经验、模块划分经验等总结起来构成的一系列开发技巧。扩展方便,程序写起来灵活(增加删除模块、功能方便)。
特殊的类,该类对象只能创建一个。
#include
#include
#include
#include
using namespace std;
class MyCAS
{
private:
MyCAS()
{
cout << "MyCAS()\n";
}
~MyCAS()
{
cout << "~MyCAS()\n";
}
private:
static MyCAS *m_instance;
public:
void func()
{
cout << "test" << endl;
}
static MyCAS *GetInstance()
{
if (m_instance == nullptr)
{
static CGarhuishou cg;
m_instance = new MyCAS();
}
return m_instance;
}
private:
class CGarhuishou
{
public:
CGarhuishou()
{
cout << "CGarhuishou()\n";
}
~CGarhuishou()
{
if (MyCAS::m_instance)
{
delete MyCAS::m_instance;
MyCAS::m_instance = nullptr;
}
cout << "~CGarhuishou()\n";
}
};
};
MyCAS *MyCAS::m_instance = nullptr;
int main()
{
{
MyCAS::GetInstance()->func();
MyCAS * p_a = MyCAS::GetInstance();
p_a->func();
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
class MyCAS
{
private:
MyCAS()
{
cout << "MyCAS()\n";
}
~MyCAS()
{
cout << "~MyCAS()\n";
}
private:
static MyCAS *m_instance;
static mutex mtx;
public:
void func()
{
cout << "test" << endl;
}
static MyCAS *GetInstance()
{
if (m_instance == nullptr)
{
unique_lock u(mtx);
if (m_instance == nullptr)
{
static CGarhuishou cg;
m_instance = new MyCAS();
}
}
return m_instance;
}
private:
class CGarhuishou
{
public:
CGarhuishou()
{
cout << "CGarhuishou()\n";
}
~CGarhuishou()
{
if (MyCAS::m_instance)
{
delete MyCAS::m_instance;
MyCAS::m_instance = nullptr;
}
cout << "~CGarhuishou()\n";
}
};
};
MyCAS *MyCAS::m_instance = nullptr;
mutex MyCAS::mtx;
void mythread()
{
cout << "begin\n";
MyCAS *p_a = MyCAS::GetInstance();
p_a->func();
cout << "end\n";
}
int main()
{
{
thread t1(mythread);
thread t2(mythread);
t1.join();
t2.join();
}
cout << "main over" << endl;
return 0;
}
保证函数只被执行一次。
once_flag,结构,标记。
#include
#include
#include
using namespace std;
class MyCAS
{
private:
MyCAS()
{
cout << "MyCAS()\n";
}
~MyCAS()
{
cout << "~MyCAS()\n";
}
private:
static MyCAS *m_instance;
static once_flag g_flag;
public:
void func()
{
cout << "test" << endl;
}
static MyCAS *GetInstance()
{
if (m_instance == nullptr)
call_once(g_flag, CreateInstance);
return m_instance;
}
private:
static void CreateInstance()
{
static CGarhuishou cg;
m_instance = new MyCAS();
}
private:
class CGarhuishou
{
public:
CGarhuishou()
{
cout << "CGarhuishou()\n";
}
~CGarhuishou()
{
if (MyCAS::m_instance)
{
delete MyCAS::m_instance;
MyCAS::m_instance = nullptr;
}
cout << "~CGarhuishou()\n";
}
};
};
MyCAS *MyCAS::m_instance = nullptr;
once_flag MyCAS::g_flag;
void mythread()
{
cout << "begin\n";
MyCAS *p_a = MyCAS::GetInstance();
p_a->func();
cout << "end\n";
}
int main()
{
{
thread t1(mythread);
thread t2(mythread);
t1.join();
t2.join();
}
cout << "main over" << endl;
return 0;
}
条件变量用于线程中等待一个条件满足(其它线程通知)时,继续往下执行。
condition_variable,条件相关的类,用于等待一个条件达成。
17.8.1-1.cpp
#include
#include
#include
#include
using namespace std;
#define N 5
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
unique_lock<mutex> g(m);
msgRecvQueue.push_back(i);
this_thread::sleep_for(chrono::microseconds(20));
}
}
void outMsgRecvQueue()
{
int command;
for (int i = 0; i < N; i++)
{
bool result = outMsgLULProc(command);
if (result)
cout << "do something" << endl;
else
cout << "empty" << endl;
this_thread::sleep_for(chrono::microseconds(10));
}
}
private:
//双重锁定或者双重检查
bool outMsgLULProc(int &command)
{
if (!msgRecvQueue.empty())
{
unique_lock<mutex> g(m);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
}
return false;
}
private:
list<int> msgRecvQueue;
mutex m;
};
int main()
{
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
}
cout << "main over" << endl;
return 0;
}
17.8.1-2.cpp
#include
#include
#include
#include
#include
using namespace std;
#define N 5
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
unique_lock<mutex> g(m);
msgRecvQueue.push_back(i);
g.unlock();//
this_thread::sleep_for(chrono::milliseconds(2));
cond.notify_one();
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
unique_lock<mutex> g(m);
// cond.wait(g)等价于cond.wait(g, []{ return false; });
// lambda表达式返回true,wait直接返回;
// lambda表达式返回false,wait将解锁互斥并堵塞到这行,直到其它线程调用notify。
// wait第二次参数是个可调用对象
//[this|&]()或者[this|&]
cond.wait(g, [&]{ return !msgRecvQueue.empty(); });
int command = msgRecvQueue.front();//肯定有数据
msgRecvQueue.pop_front();
g.unlock(); // unique_lock可以随时解锁,以免锁住太长时间。
cout << "do something" << endl;
this_thread::sleep_for(chrono::milliseconds(1));
}
}
private:
list<int> msgRecvQueue;
mutex m;
condition_variable cond;
};
int main()
{
{
A a;
thread inObj(&A::inMsgRecvQueue, std::ref(a));
thread outObj(&A::outMsgRecvQueue, &a);
outObj.join();
inObj.join();
}
cout << "main over" << endl;
return 0;
}
notify不能确保wait一定拿到锁,notify后wait线程不一定唤醒,notify线程可能又抢到锁。
无wait执行时,notify无任何效果。
notify_one()只唤醒一个wait线程,notify_all()唤醒所有wait线程。
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 5
class A
{
public:
void inMsgRecvQueue(int n)
{
for (int i = 0; i < N; i++)
{
{
unique_lock<mutex> g(m);
msgRecvQueue.push_back(i + 1);
// g.unlock();
}
this_thread::sleep_for(chrono::milliseconds(2));
cond.notify_all();
}
//生产结束,消息队列放入0
unique_lock<mutex> g(m);
for (int i = 0; i < n; i++)
msgRecvQueue.push_back(0);
g.unlock();
cond.notify_all();
cout << "inMsgRecvQueue over" << endl;
}
void outMsgRecvQueue()
{
while (true)
{
unique_lock<mutex> g(m);
cond.wait(g, [&]{ return !msgRecvQueue.empty(); });
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
g.unlock();
if (command == 0) //消息队列放入0,跳出循环
break;
cout << "do something" << endl;
this_thread::sleep_for(chrono::milliseconds(1));
}
cout << "outMsgRecvQueue over" << endl;
}
private:
list<int> msgRecvQueue;
mutex m;
condition_variable cond;
};
int main()
{
{
A a;
int n = 5;
vector<thread> threads(n);
for (int i = 0; i < n; i++)
threads[i] = thread(&A::outMsgRecvQueue, std::ref(a));
thread inObj(&A::inMsgRecvQueue, std::ref(a), n);
inObj.join();
for (int i = 0; i < n; i++)
threads[i].join();
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
using namespace std;
int mythread(){
cout<<this_thread::get_id()<<" start"<<endl;
this_thread::sleep_for(chrono::microseconds(10));
cout<<this_thread::get_id()<<" end"<<endl;
return 5;
}
int main()
{
{
future<int> result = async(mythread);
result.wait();//只等待线程返回,本身不返回结果。
cout<<result.get()<<endl;//卡在这里,等待子线程结束,只能调用一次。
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
using namespace std;
class A
{
public:
int mythread(int n)
{
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5;
}
};
int main()
{
{
A a;
int n = 12;
future<int> result = async(&A::mythread, &a, n);
result.wait(); //只等待线程返回,本身不返回结果。
cout << result.get() << endl; //卡在这里,等待子线程结束,只能调用一次。
}
cout << "main over" << endl;
return 0;
}
(1)launch::deferred
线程入口函数执行延迟到wait货get函数调用(此时未创建新线程),无调用则线程不执行。
auto result = async(launch::deferred, &A::mythread, &a, n);
(2)launch::async
创建时就立即执行(异步任务在新线程执行)。
auto result = async(launch::deferred, &A::mythread, &a, n);
(3)launch::deferred | launch::async
系统自行决定同步(无新线程)或异步(创建新线程)。
(4)无额外参数,同(3)
std::async和std::thread的区别
thread不容易拿到线程返回值,一般通过指针;
async通过future拿到。
thread创建线程太多,可能失败或崩溃;async一般不会。
std::async不确定性问题的解决
同步或异步。
类模板,模板参数是各种可调用对象,packaged_task将对象包装起来,方便作为线程入口函数使用。
#include
#include
#include
using namespace std;
int mythread(int n)
{
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5;
}
int main()
{
{
packaged_task<int(int)> mypt(mythread);
thread t(ref(mypt), 1);
future<int> result = mypt.get_future();
cout<<result.get()<<endl;
t.join();
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
{
packaged_task<int(int)> mypt([](int n) {
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5; });
thread t(ref(mypt), 1);
future<int> result = mypt.get_future();
cout << result.get() << endl;
t.join();
}
cout << "main over" << endl;
return 0;
}
packaged_task包装起来的对象可以直接调用,packaged_task对象也是一个可调用对象。
#include
#include
#include
using namespace std;
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
packaged_task<int(int)> mypt([](int n) {
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5; });
//thread t(ref(mypt), 1);
mypt(105);
future<int> result = mypt.get_future();
cout << result.get() << endl;
//t.join();
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
packaged_task<int(int)> mypt([](int n) {
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5; });
vector<packaged_task<int(int)>> mytasks;
mytasks.push_back(std::move(mypt));
packaged_task<int(int)> mypt2;
auto iter = mytasks.begin();
mypt2=std::move(*iter);
mytasks.erase(iter);
mypt2(105);
future<int> result = mypt2.get_future();
cout << result.get() << endl;
}
cout << "main over" << endl;
return 0;
}
类模板,某个线程中赋值,其它线程中取值。
#include
#include
#include
#include
using namespace std;
void mythread(promise<int> &tmp, int n)
{
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
tmp.set_value(n*10);
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
}
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
promise<int> prog;
thread t(mythread, std::ref(prog), 11);
future<int> result = prog.get_future();
cout << result.get() << endl;
t.join();
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
void mythread(promise<int> &tmp, int n)
{
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
tmp.set_value(n * 10);
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
}
void mythread2(future<int> &tmp)
{
cout << tmp.get() << endl;//get只能调用一次
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
}
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
promise<int> prog;
thread t1(mythread, std::ref(prog), 11);
t1.join();
future<int> result = prog.get_future();
// cout << result.get() << endl;//get只能调用一次
thread t2(mythread2, std::ref(result));
t2.join();
}
cout << "main over" << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
int mythread()
{
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5;
}
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
future<int> result = async(mythread);
// future result = async(launch::deferred, mythread);
future_status status = result.wait_for(chrono::microseconds(8));
switch (status)
{
case future_status::timeout: //超时未执行完
cout << result.get() << endl;
break;
case future_status::ready: //执行完
cout << result.get() << endl;
break;
case future_status::deferred: //延迟未执行
cout << result.get() << endl;
break;
}
}
cout << "main over" << endl;
return 0;
}
//异步执行
future<int> result = async(launch::async, mythread);
future移动语义,get只能调用一次;
shared_future数据复制非转移,get可调用多次。
#include
#include
#include
#include
using namespace std;
int mythread(int n)
{
cout << n << endl;
cout << this_thread::get_id() << " start" << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
return 5;
}
void mythread2(shared_future<int> &tmp)
{
cout << this_thread::get_id() << " start" << endl;
cout << tmp.get() << endl;
this_thread::sleep_for(chrono::microseconds(10));
cout << this_thread::get_id() << " end" << endl;
}
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
packaged_task<int(int)> mypt(mythread);
thread t1(ref(mypt), 1);
t1.join();
future<int> result = mypt.get_future();
bool ifcanget = result.valid(); //未调用过get,true
// auto mythreadresult = result.get();//只能get一次
// ifcanget = result.valid();//get后,false
// result未调用get,将result内容放在shared_future中,future空了
shared_future<int> result_s(move(result));
// shared_future result_s(result.share());//同上
ifcanget = result.valid(); // false,furure空了
ifcanget = result_s.valid(); // true,shared_future有内容
//可以多次调用get
auto mythreadresult = result_s.get();
mythreadresult = result_s.get();
thread t2(mythread2, ref(result_s));
t2.join();
}
cout << "main over" << endl;
return 0;
}
int main()
{
cout << "main id " << this_thread::get_id() << endl;
{
packaged_task<int(int)> mypt(mythread);
thread t1(ref(mypt), 1);
t1.join();
shared_future<int> result_s(mypt.get_future());
// shared_future result_s(result.share());//同上
//可以多次调用get
auto mythreadresult = result_s.get();
mythreadresult = result_s.get();
thread t2(mythread2, ref(result_s));
t2.join();
}
cout << "main over" << endl;
return 0;
}
一种不需要用到互斥量加锁(无锁)技术的多线程并发编程方式,在多线程中不会被打断的程序执行片段,效率更高。
互斥量加锁针对一个代码段(几行代码),原子操作针对一个变量。
原子操作指不可分割的操作,操作的状态要么完成,要么没完成。
std::atomic<int> count = 0;
void mythread(){
for(int i=0; i<1000; i++){
count++;
count += 1;
//count = count + 1;//非原子操作
}
}
++、--、+=、-=、&=、|=、^=等简单运算符是原子操作
std::atomic<bool> flag = false;
#include
#include
#include
#include
#include
using namespace std;
#define __WINDOWSLJQ__
#define N 5
class A
{
public:
A()
{
#ifdef __WINDOWSLJQ__
InitializeCriticalSection(&winsec);
#endif
}
virtual ~A()
{
#ifdef __WINDOWSLJQ__
DeleteCriticalSection(&winsec);
#endif
}
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
#ifdef __WINDOWSLJQ__
EnterCriticalSection(&winsec);
msgRecvQueue.push_back(i);
LeaveCriticalSection(&winsec);
#else
mtx.lock();
msgRecvQueue.push_back(i);
mtx.unlock();
#endif
}
}
void outMsgRecvQueue()
{
int command;
for (int i = 0; i < N; i++)
{
bool result = outMsgLULProc(command);
if (!result)
cout << "empty" << endl;
else
cout << "do something" << endl;
}
}
private:
bool outMsgLULProc(int &command)
{
#ifdef __WINDOWSLJQ__
EnterCriticalSection(&winsec);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
LeaveCriticalSection(&winsec);
return true;
}
LeaveCriticalSection(&winsec);
#else
mtx.lock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
mtx.unlock();
return true;
}
mtx.unlock();
#endif
return false;
}
private:
list<int> msgRecvQueue;
mutex mtx;
#ifdef __WINDOWSLJQ__
CRITICAL_SECTION winsec;
#endif
};
int main()
{
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
}
cout << "main over" << endl;
return 0;
}
临界区,需要在多线程编程中进行保护的共享数据相关的代码行(区域)。
#include
#include
#include
#include
#include
using namespace std;
#define __WINDOWSLJQ__
#define N 5
class A
{
public:
A()
{
#ifdef __WINDOWSLJQ__
InitializeCriticalSection(&winsec);
#endif
}
virtual ~A()
{
#ifdef __WINDOWSLJQ__
DeleteCriticalSection(&winsec);
#endif
}
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
#ifdef __WINDOWSLJQ__
EnterCriticalSection(&winsec); //进入临界区
EnterCriticalSection(&winsec); //调用两次
msgRecvQueue.push_back(i);
LeaveCriticalSection(&winsec); //离开临界区
LeaveCriticalSection(&winsec); //也要调用两次
#else
mtx.lock();
// mtx.lock();//error
msgRecvQueue.push_back(i);
mtx.unlock();
// mtx.unlock();//error
#endif
}
}
void outMsgRecvQueue()
{
int command;
for (int i = 0; i < N; i++)
{
bool result = outMsgLULProc(command);
if (!result)
cout << "empty" << endl;
else
cout << "do something" << endl;
}
}
private:
bool outMsgLULProc(int &command)
{
#ifdef __WINDOWSLJQ__
EnterCriticalSection(&winsec);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
LeaveCriticalSection(&winsec);
return true;
}
LeaveCriticalSection(&winsec);
#else
mtx.lock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
mtx.unlock();
return true;
}
mtx.unlock();
#endif
return false;
}
private:
list<int> msgRecvQueue;
mutex mtx;
#ifdef __WINDOWSLJQ__
CRITICAL_SECTION winsec;
#endif
};
int main()
{
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
}
cout << "main over" << endl;
return 0;
}
RAII(Resource Acquisition Is Initialization)类与对象,资源获取即初始化。构造函数中初始化资源,析构函数中释放资源。只能指针、容器等用到。
#include
#include
#include
#include
#include
using namespace std;
#define __WINDOWSLJQ__
class CWinLock
{
public:
CWinLock(CRITICAL_SECTION *p) : critical(p)
{
EnterCriticalSection(critical); //进入临界区
}
~CWinLock()
{
LeaveCriticalSection(critical); //离开临界区
}
private:
CRITICAL_SECTION *critical;
};
#define N 5
class A
{
public:
A()
{
#ifdef __WINDOWSLJQ__
InitializeCriticalSection(&winsec);
#endif
}
virtual ~A()
{
#ifdef __WINDOWSLJQ__
DeleteCriticalSection(&winsec);
#endif
}
public:
void inMsgRecvQueue()
{
for (int i = 0; i < N; i++)
{
#ifdef __WINDOWSLJQ__
CWinLock wlock1(&winsec);
CWinLock wlock2(&winsec); //调用多次没问题
msgRecvQueue.push_back(i);
#else
lock_guard<mutex> g1(mtx);
// lock_guard g2(mtx);//error
msgRecvQueue.push_back(i);
#endif
}
}
void outMsgRecvQueue()
{
int command;
for (int i = 0; i < N; i++)
{
bool result = outMsgLULProc(command);
if (!result)
cout << "empty" << endl;
else
cout << "do something" << endl;
}
}
private:
bool outMsgLULProc(int &command)
{
#ifdef __WINDOWSLJQ__
EnterCriticalSection(&winsec);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
LeaveCriticalSection(&winsec);
return true;
}
LeaveCriticalSection(&winsec);
#else
mtx.lock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
mtx.unlock();
return true;
}
mtx.unlock();
#endif
return false;
}
private:
list<int> msgRecvQueue;
mutex mtx;
#ifdef __WINDOWSLJQ__
CRITICAL_SECTION winsec;
#endif
};
int main()
{
{
A a;
thread outObj(&A::outMsgRecvQueue, &a);
thread inObj(&A::inMsgRecvQueue, std::ref(a));
inObj.join();
outObj.join();
}
cout << "main over" << endl;
return 0;
}
允许同一个线程多次调用同一个recursive_mutex的lock成员函数,mutex的lock不允许连续多次调用。
class A{
public:
void test1(){
lock_guard<recursive_mutex > g(mtx);
}
void test2(){
lock_guard<recursive_mutex > g(mtx);
test1();
}
private:
recursive_mutex mtx;
};
std::timed_mutx带超时功能的独占互斥锁;std::recursive_timed_mutex带超时功能的递归的独占互斥锁。
std::timed_mutx mtx;
for(int i=0; i<1000; i++){
chrono::milliseconds timeout(100);
if(mtx.try_lock_for(timeout)){
//if(mtx.try_lock_until(chrono::steady_clock::now() + timeout)){
//....
mtx.unlock();
}else{
this_thread::sleep_for(chrono::milliseconds(300));
}
}
wait线程醒来后没有实际可供处理的数据,叫虚假唤醒。
比如,push_back一条数据,调用多次notify_one,或者多个线程取数据,总有个线程唤醒后,但队列中没有数据可处理。
一般while替换if。
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 5
class A
{
public:
void inMsgRecvQueue(int n)
{
for (int i = 0; i < N; i++)
{
{
unique_lock<mutex> g(m);
msgRecvQueue.push_back(i + 1);
// g.unlock();
}
this_thread::sleep_for(chrono::milliseconds(2));
cond.notify_all();
}
//生产结束,消息队列放入0
unique_lock<mutex> g(m);
for (int i = 0; i < n; i++)
msgRecvQueue.push_back(0);
g.unlock();
cond.notify_all();
cout << "inMsgRecvQueue over" << endl;
}
void outMsgRecvQueue()
{
while (true)
{
unique_lock<mutex> g(m);
//cond.wait(g, [&]{ return !msgRecvQueue.empty(); });
while(msgRecvQueue.empty())
cond.wait(g);
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
g.unlock();
if (command == 0) //消息队列放入0,跳出循环
break;
cout << "do something" << endl;
this_thread::sleep_for(chrono::milliseconds(1));
}
cout << "outMsgRecvQueue over" << endl;
}
private:
list<int> msgRecvQueue;
mutex m;
condition_variable cond;
};
int main()
{
{
A a;
int n = 5;
vector<thread> threads(n);
for (int i = 0; i < n; i++)
threads[i] = thread(&A::outMsgRecvQueue, std::ref(a));
thread inObj(&A::inMsgRecvQueue, std::ref(a), n);
inObj.join();
for (int i = 0; i < n; i++)
threads[i].join();
}
cout << "main over" << endl;
return 0;
}
atomic禁用拷贝构造函数和复制赋值运算符。
atomic<int> atm1;
atm1 = 0;
atomic<int> atm3;
//atm3 = atm1;//error
atomic<int> atm5(atm1.load());
atm5.store(12);
atm5 = 12;
程序中偶尔达成某种条件时就创建一个线程,不够稳定。
线程池将一堆线程放在一起,进行统一的管理调度。
一般2000各左右线程就是极限,一个进程线程数不要超过500,200以内最好。