1.std::future
用来获取异步线程计算结果返回值
future的get函数设计是移动语义(move),移动后清空,所以数据只能get一次
int mythread()
{
cout<<"mythread starat ,ThreadID is"<<std::this_thread::get_id()<<endl;
std::chrono::millseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread end,ThreadID is<<std::this_thread::get_id()<<endl;
return 5;
}
int main()
{
cout<<"main thread start,threadId is "<<std::this_thread::get_id()<<endl;
std::future<int> result=std::async(thread);
cout<<"Go on!"<<endl;
//The program will be stuck,until the result get the return value.
cout<<result.get()<<endl;
cout<<"Main finish"<<endl;
return 0;
}
2.std:future_status::timeout & std::future_status::ready
一个枚举类型,用来标记和判断线程运行是否超时和完成
int mythread()
{
cout<<"mythread starat ,ThreadID is"<<std::this_thread::get_id()<<endl;
std::chrono::millseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread end,ThreadID is<<std::this_thread::get_id()<<endl;
return 5;
}
int main()
{
cout<<"main thread start,threadId is "<<std::this_thread::get_id()<<endl;
std::future<int> result=std::async(mythread);
cout<<"Go on!"<<endl;
//1.main thread wait 8 seconds
std::future_status mstatus=result.wait_for(std::chrono::seconds(8));
//In 8 seconds,mythread finish & return the value ,mstatus != timeout,=ready
//2.main thread wait 1 seconds
//std::future_status mstatus=result.wait_for(std::chrono::seconds(1));
//In 1 seconds,mythread doesn't finish & return the value ,mstatus == timeout
if(mstatus==future_status::timeout)
{
cout<<"Mythread doesn't finish"<<endl;
}
else if(mstatus==future_status::ready)
{
cout<<"Mythread finish"<<endl;
cout<<result.get()<<endl;
}
return 0;
}
3.future_status::deferred
延迟触发运行mythread,但是在主线程中运行mythread函数,相当于函数调用。
int main()
{
cout<<"main thread start,threadId is "<<std::this_thread::get_id()<<endl;
std::future<int> result=std::async(std::launch::deferred,mythread);
cout<<"Go on!"<<endl;
//1.main thread wait 8 seconds
std::future_status mstatus=result.wait_for(std::chrono::seconds(8));
//In 8 seconds,mythread finish & return the value ,mstatus != timeout,=ready
if(mstatus==future_status::timeout)
{
cout<<"Mythread doesn't finish"<<endl;
}
else if(mstatus==future_status::ready)
{
cout<<"Mythread finish"<<endl;
cout<<result.get()<<endl;
}
else if(mstatus==std::future_status::deferred)//延迟
{
//if async的第一次参数被设置为deferred,则成立
cout<<"Thread defer<<endl;
cout<<result.get()<<endl;//当运行到get时,mythread才开始执行。wait_for失效
}
return 0;
}
4.std::shared_future
也是一个类模板。
std::future的get()函数move数据。
std::shared_future的get()函数复制数据.多个线程(mythread2&mythread3)都可以获得数据。
(1)判断分享数据是否存在再share
//判断型
int mythread(int mypar)
{
cout << "mythread starat ,ThreadID is" << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "The para is " << mypar << endl;
cout << "mythread end,ThreadID is"<<std::this_thread::get_id()<<endl;
return 5;
}
void mythread2(std::shared_future<int>& tmpf)
{
cout << "mythread2 start, threadID is" << std::this_thread::get_id() << endl;
auto result = tmpf.get();
cout << "mythread2 result=" << result << endl;
}
void mythread3(std::shared_future<int>& tmpf)
{
cout << "mythread3 start, threadID is" << std::this_thread::get_id() << endl;
auto result = tmpf.get();
cout << "mythread3 result=" << result << endl;
}
int main()
{
cout << "main thread start,threadId is " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)>mypt(mythread);
std::thread t1(std::ref(mypt), 101);
t1.join();
std::future<int>result = mypt.get_future();
bool ifcanget = result.valid();//vaild判断result中是否含有值,有true,没有false
if (ifcanget == true)
{
//std::shared_future<int>result_s(std::move(result));//通result.share()
std::shared_future<int>result_s(result.share());//把result的值移动到result_s中去
auto mythreadresult = result_s.get();
std::thread t2(mythread2, ref(result_s));
t2.join();
std::thread t3(mythread3, ref(result_s));
t3.join();
}
return 0;
}
(2)不判断分享数据是否存在直接share。
//不判断,直接share。
int main()
{
cout << "main thread start,threadId is " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)>mypt(mythread);
std::thread t1(std::ref(mypt), 101);
t1.join();
//std::future<int>result = mypt.get_future();
std::shared_future<int> result_s(mypt.get_future());
auto mythreadresult = result_s.get();
thread t2(mythread2, std::ref(result_s));
thread t3(mythread3, std::ref(result_s));
t2.join();
t3.join();
cout << "Result_s.get() is" << mythreadresult << endl;
return 0;
}
5.std::atomic
原子操作(不可分割的操作),无锁技术的多线程并发方式,在多线程中不会被打断的程序执行片段。
互斥量加锁一般是针对一个代码段,而原子操作针对的是一个变量,而不是一个代码段。
一般用来统计数据发送和接受的数量。
问题代码,双线程执行使用同一个函数对全局变量进行大数据量的操作的时候因为线程片切换,导致无法完整的进行预期的操作会出现数据量不足的问题。(读取中间值问题)
预期 g_count 最终结果为2000000,实际结果为130000左右。
static int g_count=0;
void mythread()
{
for (int i = 0; i < 1000000; i++)
{
g_count++;
}
}
int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
t1.join();
t2.join();
cout << "G_count is " << g_count << endl;
return 0;
}
中间值?
写了个测试代码
结果显示不论线程1还是线程2,i 都能加到9999,但是结果却不是2W。那么中间值的问题就是线程在切换的时候,1线程的g_count 是200,时间片切换到2线程,2线程的g_count数到100,切换时间片。但是这个时候,1线程的g_cout计数从100开始,也就损失了100个计数。这个就是中间值问题。
std::mutex g_mutex;
void mythread()
{
for (int i = 0; i < 10000; i++)
{
//cout << "thread is" << _threadid << ", i is" << i << endl;
//g_mutex.lock();
g_count++;
if (i > 9990)
{
cout << "ThreadId is " << _threadid << ", i is " << i << endl;
}
//g_mutex.unlock();
}
}
int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
t1.join();
t2.join();
cout << "G_count is " << g_count << endl;
return 0;
}
解决方法一:互斥量,效率低
static int g_count=0;
std::mutex g_mutex;
void mythread()
{
for (int i = 0; i < 1000000; i++)
{
g_mutex.lock();
g_count++;
g_mutex.unlock();
}
}
int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
t1.join();
t2.join();
cout << "G_count is " << g_count << endl;
return 0;
}
解决方法二:原子操作std::atomic,效率高
c++11,一个类模板。
std::atomic<int> g_count = 0;
void mythread()
{
for (int i = 0; i < 1000000; i++)
{
g_count++;
}
}
int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
t1.join();
t2.join();
cout << "G_count is " << g_count << endl;
return 0;
}
原子操作不支持双目运算符!!
不支持+,-,*,/,会返回异常数据。
void mythread()
{
for (int i = 0; i < 100000; i++)
{
g_count++;//输出200000,正确
g_count += 1;//输出200000,正确
g_count = g_count + 1;//错误,不是所有运算符都支持原子操作
//一般原子操作,针对++,--,+=,&=,|=是支持的
}
}
bool型atomic
用来控制代码段
std::atomic<bool>g_ifend = false;//防止多线程同时写入数据时乱套。
void mythread()
{
std::chrono::milliseconds dura(1000);
while (g_ifend == false)
{
//如果为false,则系统未要修此线程退出,线程继续执行。
cout << "Thred ID is " << _threadid << endl;
std::this_thread::sleep_for(dura);
}
cout << "Thread end, ID is " << _threadid << endl;
return;
}
int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
std::chrono::seconds dura(5);
std::this_thread::sleep_for(dura);
//因为是线程中运行的是while循环,如果结束条件在join()语句下方,那么会因为joim阻塞语句,产生死循环
//所以当线程需要,函数外判定结束时,判定语句一定要在join之前执行。
g_ifend = true;//让原子对象,自行了断。
t1.join();
t2.join();
return 0;
}