promiseFuture

Promise and Future

With std::promise and std::future, you have full control over the task.

Full control over the task

A std::promise permits

  • to set a value, a notification, or an exception. That result can, in addition, be delayed provided by the promise.

A std::future permits to

  • pick up of the value from the promise.
  • asks the promise if the value is available.
  • wait for the notification of the promise. That waiting can be done with a relative time duration or an absolute time point. => Replacement for condition variables.
  • create a shared future (std::shared_future).

 

Both communication endpoints promise and the future can be moved in a separate thread. So the communication is taking place between threads.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    // promiseFuture.cpp
    
    #include <future>
    #include <iostream>
    #include <thread>
    #include <utility>
    
    void product(std::promise<int>&& intPromise, int a, int b){
      intPromise.set_value(a*b);
    }
    
    struct Div{
    
      void operator() (std::promise<int>&& intPromise, int a, int b) const {
        intPromise.set_value(a/b);
      }
    
    };
    
    int main(){
    
      int a= 20;
      int b= 10;
    
      std::cout << std::endl;
    
      // define the promises
      std::promise<int> prodPromise;
      std::promise<int> divPromise;
    
      // get the futures
      std::future<int> prodResult= prodPromise.get_future();
      std::future<int> divResult= divPromise.get_future();
    
      // calculate the result in a separat thread
      std::thread prodThread(product,std::move(prodPromise),a,b);
      Div div;
      std::thread divThread(div,std::move(divPromise),a,b);
    
      // get the result
      std::cout << "20*10= " << prodResult.get() << std::endl;
      std::cout << "20/10= " << divResult.get() << std::endl;
    
      prodThread.join();
      
      divThread.join();
    
      std::cout << std::endl;
    
    }
    

     

    The thread prodThread (line 36) uses the function product (line 8 -10), the prodPromise (line 32), and the numbers a and b. To understand the arguments of the thread prodThread, you have to look at the function’s signature. prodThread needs as the first argument a callable. This is the already mentioned function product. product needs a promise of the kind rvalue reference (std::promise<int>&& intPromise) and two numbers. These are exactly the last three arguments of the thread prodThread. std::move in line 36 creates the rvalue reference. The rest is a piece of cake. The thread divThread (line38) divides the two numbers a and b. For is a job, it uses the instances div of the class Div (line 12 – 18). div is a function object.

    The futures picks up the results by the calls prodResult.get() and divResult.get()

    promiseFuture

    Per default, there is a one-to-one relationship between the promise and the future. But std::shared_future supports a one-to-many relation between a promise and many futures.

    std::shared_future

    A std::shared_future 

    • permits you to ask the promise independent of the other associated futures.
    • has the same interface as a std::future.
    • can be created by a std::future fut with the call fut.share().
    • can be created by a std::promise divPromise with the call std::shared_future<int> divResult= divPromise.get_future().

    The managing of std::shared_future is special.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    // sharedFuture.cpp
    
    #include <exception>
    #include <future>
    #include <iostream>
    #include <thread>
    #include <utility>
    
    std::mutex coutMutex;
    
    struct Div{
    
      void operator()(std::promise<int>&& intPromise, int a, int b){
        try{
          if ( b==0 ) throw std::runtime_error("illegal division by zero");
          intPromise.set_value(a/b);
        }
        catch (...){
          intPromise.set_exception(std::current_exception());
        }
      }
    
    };
    
    struct Requestor{
    
      void operator ()(std::shared_future<int> shaFut){
    
        // lock std::cout
        std::lock_guard<std::mutex> coutGuard(coutMutex);
    
        // get the thread id
        std::cout << "threadId(" << std::this_thread::get_id() << "): " ;
    
        // get the result
        try{
          std::cout << "20/10= " << shaFut.get() << std::endl;
        }
        catch (std::runtime_error& e){
          std::cout << e.what() << std::endl;
        }
      }
    
    };
    
    int main(){
    
      std::cout << std::endl;
    
      // define the promises
      std::promise<int> divPromise;
    
      // get the futures
      std::shared_future<int> divResult= divPromise.get_future();
    
      // calculate the result in a separat thread
      Div div;
      std::thread divThread(div,std::move(divPromise),20,10);
    
      Requestor req;
      std::thread sharedThread1(req,divResult);
      std::thread sharedThread2(req,divResult);
      std::thread sharedThread3(req,divResult);
      std::thread sharedThread4(req,divResult);
      std::thread sharedThread5(req,divResult);
    
      divThread.join();
    
      sharedThread1.join();
      sharedThread2.join();
      sharedThread3.join();
      sharedThread4.join();
      sharedThread5.join();
    
      std::cout << std::endl;
    
    }
    

     

    Both work packages of the promise and the future are in this current example function objects. If you divide into numbers, you must take care of the denominator. It must not be 0. If it is 0, you get an exception. The promise deals with this issue by catching the exception (lines 18 – 20) and rethrowing it to the future. The std::future catches the exception and displays it in line 40. In line 58, divPromise will be moved and executed in divThread. Accordingly, the std::shared_future’s are copied in the five threads. I will emphasize this once more. In opposite to a std::future object, which can only be moved, you can copy a std::shared_future object.

    The main thread waits In lines 69 to 73 for its children and shows the results.

    sharedFuture

    What’s next?

    There is one oddity with std::async, which you should know. The by std::async created future blocks in its destructor until the associated promise is done. Curious? Read the next post.

     

     

     

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, moon, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *