How to implement async waiting loop with packaged_task in C++? - c++

Let us say, that we use packaged_task for implementing async work in a program.
#include <map>
#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <future>
#include <thread>
#include <chrono>
int main()
{
std::packaged_task<int()> packagedTaskOne([]()
{
using namespace std::chrono_literals;
std::this_thread::sleep_for(4s);
return 4;
});
std::future<int> futureResultOne = packagedTaskOne.get_future();
std::thread tOne(std::move(packagedTaskOne));
futureResultOne.wait();
tOne.join();
std::cout << "done\n";
return 0;
}
I can barely imagine how to implement waiting cursor in C#, because I can use something like while(!Task.Run(async () => await _service.GetValue()).IsCompleted) and output some dots that show loading. I want the same with packaged_task but I do not understand how to fuse it with while loop because I do not get what a condition I should for checking is this thread completed. How to make the same loop in C++ with packaged_task?

If you don't want to use futureResultOne.get(); to avoid blocking, the following is a way to check if your task has finished or not in the main (you can use an independent one of course) thread.
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
#include <condition_variable>
using namespace std::chrono_literals;
std::condition_variable cv;
bool theThreadHasFinished;
std::mutex mut;
int main()
{
std::packaged_task<int()> packagedTaskOne([]{
std::this_thread::sleep_for(4s);
return 4;
});
std::future<int> futureResultOne = packagedTaskOne.get_future();
std::thread tOne([&]{packagedTaskOne();
std::lock_guard lg{mut};
theThreadHasFinished = true;
cv.notify_all();});
tOne.detach();
std::unique_lock<std::mutex> lock{ mut };
cv.wait(lock, [ ](){ return theThreadHasFinished; });
std::cout << "done\n";
return 0;
}
You can use a while loop ad wait_for but this consumes your resources

Related

Problem with function push_back() and push_front() with class list in c++

I'm trying to do this simple program, where I want to use the take and append functions, which access a buffer implemented with a list, in a producer-consumer problem:
#ifndef buf_h
#define buf_h
#include <list>
using std::list;
#include <mutex>
using std::mutex;
#include <condition_variable>
using std::condition_variable;
class Buffer
{
public:
Buffer(int cap);
void append(int shift);
int take();
private:
list<double> Buffer_;
int capacity_;
int count_;
mutex mutex_;
condition_variable not_full_;
condition_variable not_empty_;
};
#endif
This is buffer:
#include "buf.h"
#include <list>
using std::list;
#include <mutex>
using std::mutex;
using std::unique_lock;
#include <condition_variable>
using std::condition_variable;
Buffer::Buffer(int capacity)
: Buffer_(capacity,0), capacity_{capacity}, count_{0}
{
}
void Buffer::append(int shift)
{
unique_lock<mutex> mlock(mutex_);
while(count_== capacity_)
not_full_.wait(mlock);
Buffer_.push_back(shift);
++count_;
not_empty_.notify_one();
}
int Buffer::take()
{
unique_lock<mutex> mlock(mutex_);
while(count_ == 0)
not_empty_.wait(mlock);
int w = Buffer_.front();
Buffer_.pop_front();
--count_;
not_full_.notify_one();
return w;
}
This is main:
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <thread>
using std::thread;
#include "buf.h"
Buffer B1{20};
void producer(int id){
B1.append(id);
}
void consumer(){
int w = B1.take();
cout<< w <<endl;
}
int main()
{
for(int i=0; i<5; ++i){
thread prod(producer, i);
thread cons(consumer);
prod.join();
cons.join();
}
return 0;
}
I don't understand why if I use push_back() in append, I get all 0 as output, when instead I should get this:
0
1
2
3
4
If I use push_front() the output is correct. Can anyone help me?
In your constructor:
Buffer_(capacity,0)
This does not do what you think it does. If you inspect what's in the Buffer_ immediately after construction you will discover that it's not empty, and the resulting program's behavior becomes easy to explain.
TLDR: the initializes the buffer with a whole bunch of values, which are all 0, which completely messes up the logic in the rest of the code which assumes that the buffer is initially empty.

Using boost::asio::post for a function that takes in parameters

I'm new to using boost, and threadpools. I want to pass a function to a threadpool that takes a variable as a parameter. In this simple example I'm just passing in an integer. My understanding is post is going to call an available thread in the thread pool to do something. The code compiles if I set up printProduct to not take in any variables, but that's not what I'm eventually trying to do.
References to relevant documentation would be very helpful (I haven't successfully found much discussion of boost::asio::post), as well as advice on how to solve the problem. Thanks!
#include <cstdlib>
#include <iostream>
#include <pthread.h>
#include <boost/version.hpp> // version is 1.72
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_pool.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/post.hpp>
#include <boost/lockfree/queue.hpp>
using namespace std;
int printProduct(int endval){
// int endval = 1000000;
int prod = 1;
for (int i=0;i<endval;i++){
prod = prod * i;
}
return prod;
}
int main() {
boost::asio::thread_pool tp(8);
for (int i =0; i<200; i++){
// issue is how to pass the parameter into post
boost::asio::post(tp, printProduct,i);
// boost::asio::post(tp, printProduct(i));
}
}
boost::asio::post takes any callable object. Requirements for such object you can find here.
There are many ways to achive what you want:
[1] lambda expressions
boost::asio::post(tp, [i]{ printProduct(i); });
[2] bind
boost::asio::post(tp, std::bind(printProduct,i));
[3] custom functor class
struct Wrapper {
int i;
Wrapper(int i) : i(i) {}
void operator()() {
printProduct(i);
}
};
boost::asio::post(Wrapper{i});

C++ Compilation error about running io_context in different thread

I am trying to use the asio::io_context in multiple threads.
#include <iostream>
#include <vector>
#include <asio.hpp>
#include <thread>
#include <future>
#include <functional>
int main()
{
asio::io_context ctx;
std::vector<std::future<asio::io_context::count_type>> tasks;
for(int i = 0; i < 3; ++i)
{
tasks.push_back(std::async(std::launch::async, std::bind(&asio::io_context::run, &ctx));
}
for(auto &task: tasks){tasks.get();}
return 0;
}
However, I am getting a compilation error
asio_blah.cpp: In function ‘int main()’:
asio_blah.cpp:101:94: error: no matching function for call to ‘bind(<unresolved overloaded function type>, asio::io_context*)’
tasks.push_back(std::async(std::launch::async, std::bind(&asio::io_context::run, &ctx));
Not sure whey the compiler is not able to figure the member function pointer ( I believe the member func type is asio::io_context::count_type (asio::io_context*)() and the function signature should visible to the compiler since asio.hpp is included) and report the error unresolved overloaded function type.
Any suggestions to fix the error?
You may go for lambda something like this:
#include <iostream>
#include <vector>
#include <boost/asio.hpp>
#include <thread>
#include <future>
#include <functional>
using namespace boost;
int main()
{
asio::io_context ctx;
std::vector<std::future<asio::io_context::count_type>> tasks;
for(int i = 0; i < 3; ++i)
{
tasks.push_back(std::async(std::launch::async, [&ctx]() {
return ctx.run();
}));
}
for(auto &task: tasks){task.get();}
return 0;
}
Edit:
As rightly said by Miles Budnek, io_context::run has multiple overloads. You cannot take a pointer to it without forcing overload resolution with a cast.
If you really want to use std::bind, go for casting.
My opinion is same as that of others. GO FOR LAMBDA!!!

Using a boost::asio::deadline_timer per thread not working

I'm newbie here, so if I have any errors just tell me.
The problem is that I have two processes and I want them to execute concurrently because they take too much time. So I thought to implement a class timer which manage its own boost::asio::io_service and create a thread for this io_service. The code is the following:
timer.hpp
#include <iostream>
#include <string>
#include <functional>
#include <thread>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
class timer
{
public:
timer(std::function<void(void)> task,
int time)
: io__(),
timer__(io__, boost::posix_time::milliseconds(time)),
repetitive_task__(task),
time_wait__(time)
{
timer__.async_wait(boost::bind(&timer::loop, this));
}
void start()
{
thread__ = std::thread([this](){
io__.run();
});
thread__.join();
}
void loop()
{
repetitive_task__();
timer__.expires_at(timer__.expires_at() + boost::posix_time::milliseconds(time_wait__));
timer__.async_wait(boost::bind(&timer::loop, this));
}
void stop()
{
timer__.cancel();
io__.stop();
}
private:
boost::asio::io_service io__;
boost::asio::deadline_timer timer__;
std::function<void(void)> repetitive_task__;
int time_wait__;
std::thread thread__;
};
For testing it, I have the simplest main I could think:
main.cpp
#include "timer.hpp"
void test1()
{
printf("action1 \n");
}
void test2()
{
printf("action 2 \n");
}
int main(int argc, char* argv[])
{
timer timer1(&test1, 100);
timer timer2(&test2, 50);
timer1.start();
timer2.start();
return 0;
}
And the result is always action1. Never action2.
I've been looking for how to implement timers properly like in this post or in this example of boost, but I still don't understand what I am doing wrong.
Thanks in advance

Why doesn't future::wait() block

#include <iostream>
#include <string>
#include <thread>
#include <future>
int main()
{
auto pms = std::promise<std::string>();
auto ftr = pms.get_future();
std::thread([&](){pms.set_value("hello world");});
ftr.wait();
std::cout << ftr.get() << std::endl;
return 0;
}
According to this link, std::future::wait blocks until the result becomes avaiable.
However, the code above can't print anything. Obviously the main thread has finished before the thread of pms.set_value finished.
Why doesn't ftr.wait() block?
The problem is not that std::future::wait doesn't block. The real problem is that you have a race condition between the thread that you spawned, doing it's work, and the destruction of std::thread (temporary) object in the main thread.
Because of that, abort is called in the destructor of std::thread if the thread is still joinable.
Working code:
#include <iostream>
#include <string>
#include <thread>
#include <future>
#include <chrono>
int main()
{
auto pms = std::promise<std::string>();
auto ftr = pms.get_future();
std::thread thread ([&](){pms.set_value("hello world");});
ftr.wait();
std::cout << ftr.get() << std::endl;
thread.join ();
return 0;
}
Note, if you don't join the thread explicitly, you would still have the same race condition (since it's possible that main can do its work faster, than the thread can clean itself up.
Demo of working example: here.
Alternatively you can detach the thread and use promise::set_value_at_thread_exit rather than set_value
#include <iostream>
#include <string>
#include <thread>
#include <future>
#include <chrono>
int main()
{
auto pms = std::promise<std::string>();
auto ftr = pms.get_future();
std::thread([&](){pms.set_value_at_thread_exit("hello world");}).detach();
ftr.wait();
std::cout << ftr.get() << std::endl;
return 0;
}