1. std :: futureは
、非同期スレッド計算結果の戻り値を取得するために使用されます。future
のget関数の設計はmoveセマンティクス(move)であり、move後にクリアされるため、データは1回しか取得できません。
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
delayは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()関数はデータを移動します。
std :: shared_futureのget()関数はデータをコピーします。複数のスレッド(mythread2&mythread3)がデータを取得できます。
(1)共有データが存在するかどうかを確認してから共有する
//判断型
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。
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 ::アトミック
アトミック操作(分離不可能な操作)、ロックテクノロジのないマルチスレッド同時実行モード、マルチスレッドで中断されないプログラム実行フラグメント。
ミューテックスロックは一般にコードセグメント用ですが、アトミック操作は変数用であり、コードセグメント用ではありません。
通常、送受信されたデータの数をカウントするために使用されます。
問題コード、2スレッド実行が同じ関数を使用してグローバル変数に対して大規模なデータ操作を実行する場合、スレッドスライスの切り替えのために、期待される操作を完全に実行できず、データが不足します。(中間値の問題の読み取り)
g_countの最終結果は2000000になると予想され、実際の結果は約130,000です。
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に関係なく、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;
}
解決策1:ミューテックス、低効率
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;
}
解決策2:アトミック操作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;//错误,不是所有运算符都支持原子操作
//一般原子操作,针对++,--,+=,&=,|=是支持的
}
}
ブール型アトミックは
、コードセグメントを制御するために使用されます
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;
}