C++
वायदा और वादा
खोज…
परिचय
वादे और वायदे का उपयोग किसी एक वस्तु को एक धागे से दूसरे धागे में बांधने के लिए किया जाता है।
एक std::promise
ऑब्जेक्ट थ्रेड द्वारा सेट किया गया है जो परिणाम उत्पन्न करता है।
एक std::future
वस्तु का उपयोग किसी मान को प्राप्त करने के लिए किया जा सकता है, यह देखने के लिए कि क्या कोई मूल्य उपलब्ध है या मूल्य उपलब्ध होने तक निष्पादन को रोक दिया जाए।
एसटीडी :: भविष्य और एसटी :: वादा
निम्नलिखित उदाहरण एक और धागे द्वारा खपत होने का वादा करता है:
{
auto promise = std::promise<std::string>();
auto producer = std::thread([&]
{
promise.set_value("Hello World");
});
auto future = promise.get_future();
auto consumer = std::thread([&]
{
std::cout << future.get();
});
producer.join();
consumer.join();
}
आस्थगित async उदाहरण
यह कोड std::async
का एक संस्करण लागू करता है, लेकिन यह ऐसा व्यवहार करता है जैसे कि async
को हमेशा deferred
लॉन्च नीति के साथ कहा जाता है। इस फ़ंक्शन में भी async
का विशेष future
व्यवहार नहीं है; लौटाया गया future
कभी भी उसका मूल्य प्राप्त किए बिना नष्ट हो सकता है।
template<typename F>
auto async_deferred(F&& func) -> std::future<decltype(func())>
{
using result_type = decltype(func());
auto promise = std::promise<result_type>();
auto future = promise.get_future();
std::thread(std::bind([=](std::promise<result_type>& promise)
{
try
{
promise.set_value(func());
// Note: Will not work with std::promise<void>. Needs some meta-template programming which is out of scope for this example.
}
catch(...)
{
promise.set_exception(std::current_exception());
}
}, std::move(promise))).detach();
return future;
}
std :: packaged_task और std :: भविष्य
std::packaged_task
एक फ़ंक्शन और इसके वापसी प्रकार के लिए संबद्ध वादा को बंडल करता है:
template<typename F>
auto async_deferred(F&& func) -> std::future<decltype(func())>
{
auto task = std::packaged_task<decltype(func())()>(std::forward<F>(func));
auto future = task.get_future();
std::thread(std::move(task)).detach();
return std::move(future);
}
धागा तुरंत चलने लगता है। हम या तो इसे अलग कर सकते हैं, या दायरे के अंत में इसे शामिल कर सकते हैं। जब फ़ंक्शन std :: थ्रेड को पूरा करता है, तो परिणाम तैयार है।
ध्यान दें कि यह से थोड़ा भिन्न है std::async
जहां लौटे std::future
जब वास्तव में जब तक धागा समाप्त हो गया है को अवरुद्ध कर देगा विलुप्त।
std :: future_error और std :: future_errc
अगर std के लिए अड़चनें :: वादा और std :: भविष्य के प्रकार std के अपवाद को पूरा नहीं किया जाता है :: future_error फेंक दिया जाता है।
अपवाद में त्रुटि कोड सदस्य प्रकार std :: Future_errc और मान नीचे दिए गए हैं, साथ ही कुछ परीक्षण मामले:
enum class future_errc {
broken_promise = /* the task is no longer shared */,
future_already_retrieved = /* the answer was already retrieved */,
promise_already_satisfied = /* the answer was stored already */,
no_state = /* access to a promise in non-shared state */
};
निष्क्रिय वादा:
int test()
{
std::promise<int> pr;
return 0; // returns ok
}
सक्रिय वादा, अप्रयुक्त:
int test()
{
std::promise<int> pr;
auto fut = pr.get_future(); //blocks indefinitely!
return 0;
}
दोहरी पुनर्प्राप्ति:
int test()
{
std::promise<int> pr;
auto fut1 = pr.get_future();
try{
auto fut2 = pr.get_future(); // second attempt to get future
return 0;
}
catch(const std::future_error& e)
{
cout << e.what() << endl; // Error: "The future has already been retrieved from the promise or packaged_task."
return -1;
}
return fut2.get();
}
सेटिंग std :: वादा मूल्य दो बार:
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
try{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
pr2.set_value(10); // second attempt to set promise throws exception
}
catch(const std::future_error& e)
{
cout << e.what() << endl; // Error: "The state of the promise has already been set."
return -1;
}
return fut.get();
}
std :: भविष्य और std :: async
निम्न भोले समानांतर मर्ज सॉर्ट उदाहरण में, std::async
का उपयोग कई समानांतर मर्ज_सॉर्ट कार्य को लॉन्च करने के लिए किया जाता है। std::future
का उपयोग परिणामों की प्रतीक्षा करने और उन्हें सिंक्रनाइज़ करने के लिए किया जाता है:
#include <iostream>
using namespace std;
void merge(int low,int mid,int high, vector<int>&num)
{
vector<int> copy(num.size());
int h,i,j,k;
h=low;
i=low;
j=mid+1;
while((h<=mid)&&(j<=high))
{
if(num[h]<=num[j])
{
copy[i]=num[h];
h++;
}
else
{
copy[i]=num[j];
j++;
}
i++;
}
if(h>mid)
{
for(k=j;k<=high;k++)
{
copy[i]=num[k];
i++;
}
}
else
{
for(k=h;k<=mid;k++)
{
copy[i]=num[k];
i++;
}
}
for(k=low;k<=high;k++)
swap(num[k],copy[k]);
}
void merge_sort(int low,int high,vector<int>& num)
{
int mid;
if(low<high)
{
mid = low + (high-low)/2;
auto future1 = std::async(std::launch::deferred,[&]()
{
merge_sort(low,mid,num);
});
auto future2 = std::async(std::launch::deferred, [&]()
{
merge_sort(mid+1,high,num) ;
});
future1.get();
future2.get();
merge(low,mid,high,num);
}
}
नोट: उदाहरण में std::async
को नीति std::launch_deferred
साथ लॉन्च किया गया है। यह हर कॉल में बनाए जा रहे नए धागे से बचने के लिए है। हमारे उदाहरण के मामले में, std::async
लिए कॉल आउट ऑफ ऑर्डर हो जाते हैं, वे std::future::get()
लिए कॉल पर सिंक्रनाइज़ होते हैं।
std::launch_async
हर कॉल में एक नया थ्रेड बनाने के लिए std::launch_async
।
डिफ़ॉल्ट नीति है std::launch::deferred| std::launch::async
, जिसका अर्थ है कि कार्यान्वयन नए धागे बनाने के लिए नीति निर्धारित करता है।
Async ऑपरेशन कक्षाएं
- std :: async: एक एसिंक्रोनस ऑपरेशन करता है।
- एसटीडी :: भविष्य: एक अतुल्यकालिक ऑपरेशन के परिणाम तक पहुंच प्रदान करता है।
- एसटीडी :: वादा: एक अतुल्यकालिक ऑपरेशन का परिणाम संकुल।
- std :: packaged_task: एक फ़ंक्शन और इसके वापसी प्रकार के लिए संबद्ध वादा बंडल करता है।