Skip to content

Instantly share code, notes, and snippets.

@Indy9000
Created October 1, 2019 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Indy9000/973b5a03c7a66aa9985646e29743d46d to your computer and use it in GitHub Desktop.
Save Indy9000/973b5a03c7a66aa9985646e29743d46d to your computer and use it in GitHub Desktop.
difference between threads and async
// worker threads vs async/futures
//
// This demonstrates that for heavy compute that require multiple workers that
// send the results in a queue to the caller, using async/futures is
// much simpler than using worker threads
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <future>
// our simulated heavy compute is a fibonacci computer
int fib(int n){
int p0 = 1; int p1 = 1;
if (n==0 ||n ==1) { return 1;}
int pi = 0;
for(int i=2;i<=n;i++){
pi = p1 + p0;
p0 = p1;
p1 = pi;
}
return pi;
}
// here we implement this strategy with worker threads
// simple pub sub
// we'll use fib for the pub (many) and sub (one)
void multi_fib(){
std::vector<std::thread> threads;
std::queue<std::pair<int,int>> results;
std::condition_variable cv;
std::mutex m;
std::atomic<bool> done {false};
// create worker threads that do the computation
// results are placed in a queue
for(int i=0;i<5;++i){
threads.emplace_back(
std::thread([&](int j){
auto result = fib(j*10);
{
std::lock_guard<std::mutex> lg(m);
results.emplace(std::make_pair(j,result));
cv.notify_one();
}
}, i)
);
}
// create a listner thread and receive results
auto listner = std::thread([&](){
while(!done){
std::unique_lock<std::mutex> ul(m);
cv.wait(ul,[&](){return !results.empty();});
// cv notifications are not queued, therefore
// we need to empty the queue when we get a signal
while(!results.empty()){
auto result = results.front();
results.pop();
std::cout << result.first << "," << result.second << std::endl;
}
}
});
// wait for all the worker threads to finish
std::cout << "waiting for threads to join\n";
for(auto &t : threads){
t.join();
}
// signal the listner thread that it can finish
std::cout << "setting done\n";
done = true;
// wait for the listner to finish
listner.join();
std::cout << "exiting\n";
}
// same strategy as above with async/futures
void async_fib(){
// results are placed into this vector
std::vector<std::future<int>> results;
// create workers
for(int i=0;i<5;++i){
results.emplace_back(std::async(fib,(i*10)));
}
// wait and get the results
for(auto & f:results){
std::cout << f.get() << std::endl;
}
}
int main() {
multi_fib();
async_fib();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment