A std::promise
को एक वादा / भविष्य की जोड़ी के लिए एक अंतिम बिंदु के रूप में बनाया गया है और std::future
(std से बनाया गया :: get_future()
विधि का उपयोग करने का वादा ) दूसरा अंत बिंदु है। यह एक सरल, एक शॉट विधि है जो दो थ्रेड्स के लिए एक तरीका प्रदान करती है, जैसे कि एक थ्रेड एक संदेश के माध्यम से दूसरे थ्रेड को डेटा प्रदान करता है।
आप इसे सोच सकते हैं क्योंकि एक धागा डेटा प्रदान करने का वादा करता है और दूसरा धागा भविष्य में वादा करता है। इस तंत्र का उपयोग केवल एक बार किया जा सकता है।
वादा / भविष्य का तंत्र केवल एक दिशा है, थ्रेड से जो थ्रेड की set_value()
विधि का std::promise
उपयोग करता है जो डेटा प्राप्त करने के लिए get()
ए std::future
का उपयोग करता है । यदि अपवाद उत्पन्न होता हैget()
भविष्य पद्धति को एक से अधिक बार कहा जाता है है।
यदि थ्रेड के साथ अपने वादे को पूरा करने के लिए std::promise
उपयोग नहीं किया set_value()
गया है, तो जब दूसरा थ्रेड वादा को इकट्ठा करने के लिए कहता get()
है std::future
, तो दूसरा धागा एक प्रतीक्षा स्थिति में चला जाएगा जब तक कि पहले थ्रेड के साथ वादा पूरा नहीं होता है std::promise
जब वह set_value()
विधि का उपयोग करता है डेटा भेजने के लिए।
तकनीकी विनिर्देश N4663 प्रोग्रामिंग भाषाओं के प्रस्तावित कोरआउट के साथ - कोरआउट के लिए C ++ एक्सटेंशन्स और विजुअल स्टूडियो 2017 C ++ कंपाइलर समर्थन co_await
, का उपयोग करना std::future
और std::async
कॉरआउट की कार्यक्षमता लिखना भी संभव है । में चर्चा और उदाहरण देखें https://stackoverflow.com/a/50753040/1466970 जो एक अनुभाग है कि के उपयोग पर चर्चा के रूप में है std::future
के साथ co_await
।
निम्न उदाहरण कोड, एक साधारण विज़ुअल स्टूडियो 2013 विंडोज कंसोल एप्लिकेशन, कुछ C ++ 11 संगामिति कक्षाओं / टेम्पलेट्स और अन्य कार्यक्षमता का उपयोग करके दिखाता है। यह वादा / भविष्य के लिए उपयोग को दिखाता है जो अच्छी तरह से काम करता है, स्वायत्त धागे जो कुछ कार्य करेंगे और रोकेंगे, और एक उपयोग जहां अधिक तुल्यकालिक व्यवहार की आवश्यकता होती है और कई सूचनाओं की आवश्यकता के कारण वादा / भविष्य की जोड़ी काम नहीं करती है।
इस उदाहरण के बारे में एक नोट विभिन्न स्थानों पर जोड़े गए विलंब हैं। इन देरी को केवल यह सुनिश्चित करने के लिए जोड़ा गया था कि कंसोल का उपयोग करके मुद्रित किए गए विभिन्न संदेश std::cout
स्पष्ट होंगे और कई थ्रेड्स के पाठ को आपस में जोड़ा नहीं जाएगा।
के पहले भाग main()
के लिए तीन अतिरिक्त धागे बनाने और उपयोग कर रहा है std::promise
और std::future
धागे के बीच डेटा भेजने के लिए। एक दिलचस्प बात यह है कि मुख्य धागा एक थ्रेड टी 2 शुरू करता है, जो मुख्य थ्रेड से डेटा की प्रतीक्षा करेगा, कुछ करें, और फिर तीसरे थ्रेड, T3 पर डेटा भेजें, जो तब कुछ करेगा और डेटा वापस भेजेगा। मुख्य सूत्र।
के दूसरे भाग main()
दो धागे बनाता है और मुख्य थ्रेड से दो बनाया धागे से प्रत्येक के लिए एक से अधिक संदेशों अनुमति देने के लिए कतार का एक सेट। हम इसका उपयोग नहीं कर सकते std::promise
और इसके std::future
लिए क्योंकि वादा / भविष्य की जोड़ी एक शॉट है और इसे बार-बार उपयोग नहीं किया जा सकता है।
कक्षा के लिए स्रोत Sync_queue
स्ट्रॉस्ट्रुप की द C ++ प्रोग्रामिंग भाषा: 4 वें संस्करण से है।
// cpp_threads.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <thread> // std::thread is defined here
#include <future> // std::future and std::promise defined here
#include <list> // std::list which we use to build a message queue on.
static std::atomic<int> kount(1); // this variable is used to provide an identifier for each thread started.
//------------------------------------------------
// create a simple queue to let us send notifications to some of our threads.
// a future and promise are one shot type of notifications.
// we use Sync_queue<> to have a queue between a producer thread and a consumer thread.
// this code taken from chapter 42 section 42.3.4
// The C++ Programming Language, 4th Edition by Bjarne Stroustrup
// copyright 2014 by Pearson Education, Inc.
template<typename Ttype>
class Sync_queue {
public:
void put(const Ttype &val);
void get(Ttype &val);
private:
std::mutex mtx; // mutex used to synchronize queue access
std::condition_variable cond; // used for notifications when things are added to queue
std::list <Ttype> q; // list that is used as a message queue
};
template<typename Ttype>
void Sync_queue<Ttype>::put(const Ttype &val) {
std::lock_guard <std::mutex> lck(mtx);
q.push_back(val);
cond.notify_one();
}
template<typename Ttype>
void Sync_queue<Ttype>::get(Ttype &val) {
std::unique_lock<std::mutex> lck(mtx);
cond.wait(lck, [this]{return !q.empty(); });
val = q.front();
q.pop_front();
}
//------------------------------------------------
// thread function that starts up and gets its identifier and then
// waits for a promise to be filled by some other thread.
void func(std::promise<int> &jj) {
int myId = std::atomic_fetch_add(&kount, 1); // get my identifier
std::future<int> intFuture(jj.get_future());
auto ll = intFuture.get(); // wait for the promise attached to the future
std::cout << " func " << myId << " future " << ll << std::endl;
}
// function takes a promise from one thread and creates a value to provide as a promise to another thread.
void func2(std::promise<int> &jj, std::promise<int>&pp) {
int myId = std::atomic_fetch_add(&kount, 1); // get my identifier
std::future<int> intFuture(jj.get_future());
auto ll = intFuture.get(); // wait for the promise attached to the future
auto promiseValue = ll * 100; // create the value to provide as promised to the next thread in the chain
pp.set_value(promiseValue);
std::cout << " func2 " << myId << " promised " << promiseValue << " ll was " << ll << std::endl;
}
// thread function that starts up and waits for a series of notifications for work to do.
void func3(Sync_queue<int> &q, int iBegin, int iEnd, int *pInts) {
int myId = std::atomic_fetch_add(&kount, 1);
int ll;
q.get(ll); // wait on a notification and when we get it, processes it.
while (ll > 0) {
std::cout << " func3 " << myId << " start loop base " << ll << " " << iBegin << " to " << iEnd << std::endl;
for (int i = iBegin; i < iEnd; i++) {
pInts[i] = ll + i;
}
q.get(ll); // we finished this job so now wait for the next one.
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::chrono::milliseconds myDur(1000);
// create our various promise and future objects which we are going to use to synchronise our threads
// create our three threads which are going to do some simple things.
std::cout << "MAIN #1 - create our threads." << std::endl;
// thread T1 is going to wait on a promised int
std::promise<int> intPromiseT1;
std::thread t1(func, std::ref(intPromiseT1));
// thread T2 is going to wait on a promised int and then provide a promised int to thread T3
std::promise<int> intPromiseT2;
std::promise<int> intPromiseT3;
std::thread t2(func2, std::ref(intPromiseT2), std::ref(intPromiseT3));
// thread T3 is going to wait on a promised int and then provide a promised int to thread Main
std::promise<int> intPromiseMain;
std::thread t3(func2, std::ref(intPromiseT3), std::ref(intPromiseMain));
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2 - provide the value for promise #1" << std::endl;
intPromiseT1.set_value(22);
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2.2 - provide the value for promise #2" << std::endl;
std::this_thread::sleep_for(myDur);
intPromiseT2.set_value(1001);
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2.4 - set_value 1001 completed." << std::endl;
std::future<int> intFutureMain(intPromiseMain.get_future());
auto t3Promised = intFutureMain.get();
std::cout << "MAIN #2.3 - intFutureMain.get() from T3. " << t3Promised << std::endl;
t1.join();
t2.join();
t3.join();
int iArray[100];
Sync_queue<int> q1; // notification queue for messages to thread t11
Sync_queue<int> q2; // notification queue for messages to thread t12
std::thread t11(func3, std::ref(q1), 0, 5, iArray); // start thread t11 with its queue and section of the array
std::this_thread::sleep_for(myDur);
std::thread t12(func3, std::ref(q2), 10, 15, iArray); // start thread t12 with its queue and section of the array
std::this_thread::sleep_for(myDur);
// send a series of jobs to our threads by sending notification to each thread's queue.
for (int i = 0; i < 5; i++) {
std::cout << "MAIN #11 Loop to do array " << i << std::endl;
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
q1.put(i + 100);
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
q2.put(i + 1000);
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
}
// close down the job threads so that we can quit.
q1.put(-1); // indicate we are done with agreed upon out of range data value
q2.put(-1); // indicate we are done with agreed upon out of range data value
t11.join();
t12.join();
return 0;
}
यह साधारण एप्लिकेशन निम्न आउटपुट बनाता है।
MAIN #1 - create our threads.
MAIN #2 - provide the value for promise #1
func 1 future 22
MAIN #2.2 - provide the value for promise #2
func2 2 promised 100100 ll was 1001
func2 3 promised 10010000 ll was 100100
MAIN #2.4 - set_value 1001 completed.
MAIN #2.3 - intFutureMain.get() from T3. 10010000
MAIN #11 Loop to do array 0
func3 4 start loop base 100 0 to 5
func3 5 start loop base 1000 10 to 15
MAIN #11 Loop to do array 1
func3 4 start loop base 101 0 to 5
func3 5 start loop base 1001 10 to 15
MAIN #11 Loop to do array 2
func3 4 start loop base 102 0 to 5
func3 5 start loop base 1002 10 to 15
MAIN #11 Loop to do array 3
func3 4 start loop base 103 0 to 5
func3 5 start loop base 1003 10 to 15
MAIN #11 Loop to do array 4
func3 4 start loop base 104 0 to 5
func3 5 start loop base 1004 10 to 15