I'm working on a project using C++.
I want a TimerHandler to be called after a specified time, but at the same time I don't want to block the current thread or any code after io.run() in the following code:
#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class TimerTest
{
public:
static void PrintOutTimerHandler(const boost::system::error_code&, const std::string& message)
{
std::cout << "PrintOutTimerHandler called: " << ", message: " << message << std::endl;
}
void run()
{
boost::asio::io_service io;
boost::asio::deadline_timer dt(io, boost::posix_time::seconds(5));
std::cout << "Start:\t" << std::endl;
dt.async_wait(boost::bind(PrintOutTimerHandler, boost::asio::placeholders::error, std::string("here is the message")));
// Do some job here
for (int i = 0; i < 1000000; ++i)
++i, --i;
std::cout << "End:\t" << std::endl;
io.run();
std::cout << "When to reach here 1: " << std::endl;
}
};
int main()
{
TimerTest tt;
tt.run();
std::cout << "When to reach here 2: " << std::endl;
return 0;
}
/* Current output:
Start:
End:
PrintOutTimerHandler called: , message: here is the message
When to reach here 1:
When to reach here 2:
*/
/* Expected output:
Start:
End:
When to reach here 1:
When to reach here 2:
PrintOutTimerHandler called: , message: here is the message
*/
I think I made myself clear. My questions are:
If this can be solved without
introducing a new thread, like Flex
ActionScript, that's is the best, but
I guess not (I guess ActionScript is
using a hidden thread);
If we have to
introduce an extra thread to do the
job, would you mind writing down the
pseudo code for me?
Thanks.
Peter
Here is an example . Run the io_service in a separate thread
asio::io_service io_service;
asio::thread t(boost::bind(&asio::io_service::run, &io_service));
or run it in a thread group
boost::thread_group threads;
for (std::size_t i = 0; i < my_thread_count; ++i)
threads.create_thread(boost::bind(&asio::io_service::run, &io_service));
Remember that your main thread should always run because when it exists all threads spawned will also exit.
I hope this helps.
I misunderstood what OrcunC said, but actually he is correct. Here is the modified version for your reference:
#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class TimerTest
{
public:
static void PrintOutTimerHandler(const boost::system::error_code&, const std::string& message)
{
std::cout << "PrintOutTimerHandler called: " << ", message: " << message << std::endl;
}
TimerTest(unsigned int timeout)
: dt(io, boost::posix_time::milliseconds(timeout))
{
}
void run()
{
std::cout << "Start:\t" << std::endl;
dt.async_wait(boost::bind(PrintOutTimerHandler, boost::asio::placeholders::error, std::string("here is the message")));
boost::thread thrd(boost::bind(&boost::asio::io_service::run, &io));
// Do some job here
for (int i = 0; i < 1000000; ++i)
++i, --i;
std::cout << "End:\t" << std::endl;
std::cout << "When to reach here 1: " << std::endl;
}
boost::asio::io_service io;
boost::asio::deadline_timer dt;
};
int main()
{
TimerTest tt(5000);
tt.run();
std::cout << "When to reach here 2: " << std::endl;
// Keep the main thread active for testing purpose. Otherwise,
// once the TimerTest object is destroyed when exiting the main() function,
// the sub thread spawed in tt.run() will also exit;
Sleep(10000);
}
/* Current output and Expected output:
Start:
End:
When to reach here 1:
When to reach here 2:
PrintOutTimerHandler called: , message: here is the message
*/
Related
I'm getting a crash when calling interrupt() on an outer boost::thread, which runs an inner boost::thread, which is connected to a thread_guard. It's not crashing when calling join() manually on the inner thread.
Crash:
terminate called after throwing an instance of 'boost::thread_interrupted'
Source:
https://gist.github.com/elsamuko/6e178c37fa2cf8742cb6bf512f2ff866
#include <iostream>
#include <thread>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_guard.hpp>
#define LOG( A ) std::cout << A << std::endl;
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([]{
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
});
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
LOG("Interrupting inner");
boost::thread_guard<boost::join_if_joinable> guard(inner); // crashes
// inner.join(); // works
}
});
LOG("Interrupting outer");
outer.interrupt();
outer.join();
}
int main(int argc, char* argv[]) {
LOG("Start");
double_interrupt();
LOG("End");
return 0;
}
Compile & Run:
http://coliru.stacked-crooked.com/a/46c512bf9a385fff
I'm running on Ubuntu 18.04. with g++ 7.5.0 and got the latest boost 1.78.0.
I opened this issue on github, too: https://github.com/boostorg/thread/issues/366
You're mixing std::thread and boost::thread.
Only Boost Thread knows about interruption points. Use that to fix:
Live On Coliru
#include <iostream>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/thread_guard.hpp>
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([] {
while (true) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
}
});
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
std::cout << "Interrupting inner" << std::endl;
boost::thread_guard<boost::join_if_joinable> guard(inner);
}
});
std::cout << "Interrupting outer" << std::endl;
outer.interrupt();
outer.join();
}
int main() {
std::cout << "Start" << std::endl;
double_interrupt();
std::cout << "End" << std::endl;
}
Prints
Start
Interrupting outer
End
I got a solution. The problem was, that the join() of the thread_guard waits for the inner thread with a condition_variable::wait(). condition_variable::wait() itself checks, if it's interruptible and throws an exception.
The solution is to use a custom thread_guard with disable_interruption:
#include <iostream>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/thread_guard.hpp>
#define LOG( A ) std::cout << A << std::endl;
void work() {
size_t sum = 0;
for(int i = 0; i < 1E7; ++i) { sum += 1; }
LOG("work: " << sum);
}
// helper struct to interrupt a boost::thread within a boost::thread
struct non_interruptable_interrupt_and_join_if_joinable {
template <class Thread>
void operator()(Thread& t) {
if(t.joinable()) {
boost::this_thread::disable_interruption di;
t.interrupt();
t.join();
}
}
};
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([] {
while(true) {
boost::this_thread::interruption_point();
work();
}
});
{
boost::thread_guard<non_interruptable_interrupt_and_join_if_joinable> guard(inner);
LOG("Interrupting inner");
}
});
LOG("Interrupting outer");
outer.interrupt();
outer.join();
}
int main() {
LOG("Start");
double_interrupt();
LOG("End");
}
Run here:
http://coliru.stacked-crooked.com/a/a365e40a2bd574cc
C++98 and Boost 1.54
I'm having trouble figuring out why using boost::this_thread::sleep_for is sleeping my entire program. The only time and place the Wait() function is called is inside this thread, and this thread's sole purpose is to read file names in a directory and trigger an upload.
But for some reason, when it reaches the boost::this_thread::sleep_for line in the Wait() function, it hangs there and sleeps all the other threads as well. I'm unsure what I am missing, so any help would be appreciated.
Code:
void Upload::ReadFileNames()
{
cout << "[DEBUG] ReadFileNames -> A " << endl;
Wait();
cout << "[DEBUG] ReadFileNames -> B " << endl;
// read filename stuff
}
void Upload::Wait()
{
typedef boost::chrono::duration<long, boost::ratio<60> > seconds;
int randomWaitTime = 0;
try{
randomWaitTime = lexical_cast<unsigned int>(getId());
randomWaitTime = randomWaitTime * 10;
}
catch ( const boost::bad_lexical_cast & e){
// cout << "[LOG] FileUpLoad : Wait : bad_lexical_cast : " << e.what() << endl ;
randomWaitTime = 0;
}
seconds testTimeToWait(randomWaitTime);
cout << "[DEBUG] Wait() -> A" << endl;
boost::this_thread::sleep_for(testTimeToWait);
cout << "[DEBUG] Wait() -> B" << endl;
cout << "RANDOM WAIT TIME = " << randomWaitTime << endl;
}
main.cpp
int main()
{
pthread_t threadA;
pthread_create(&threadA,NULL,threadAfn,NULL);
pthread_t threadB;
pthread_create(&threadB,NULL,threadBfn,NULL);
pthread_t Upload; // <--- Thread in question
pthread_create(&Upload,NULL,Uploadfn,NULL);
pthread_join(threadA,NULL);
pthread_join(threadB,NULL);
pthread_join(Upload,NULL); // <--- Thread in question
return 0;
}
Output
[DEBUG] ReadFileNames -> A
[DEBUG] Wait() -> A
// hangs here and rest of the threads are locked/slept as well?
it hangs there and sleeps all the other threads as well
No it doesn't. If it seems that way, that is because the other threads were already stuck or finished.
Look for things that block (mutex.lock, condition wait, IO operations, etc.) or check that the threads didn't exit.
Notes
Your seconds calculations is off. On my system, the following:
Live On Coliru
#include <boost/chrono.hpp>
#include <iostream>
int main() {
std::cout << boost::chrono::duration<long, boost::ratio<60> >(1)/boost::chrono::seconds(1) << std::endl;
}
Prints
60
So, what you named seconds is actually minutes. Just do this instead:
using boost::chrono::seconds;
int delay = std::strtoul(getId().c_str(), NULL, 10)*10;
sleep_for(seconds(delay));
Your random delay is only random if the getId return is. Using boost/random.hpp you can make it truly random, with good range control. E.g. to sleep between 1'000 and 3'000 ms:
int random_gen(int low, int high) { // not threadsafe
static boost::random_device rdev;
static boost::mt19937 prng(rdev);
return boost::uniform_int<>(low, high)(prng);
}
void Upload::Wait() {
int const ms_delay = random_gen(1000, 3000);
cout << "RANDOM WAIT TIME = " << ms_delay << endl;
sleep_for(milliseconds(ms_delay));
}
Note to seed using random_device as shown (so true random seed) you need to link the random library. Otherwise, you can "stoop" to a time-based seed:
static boost::mt19937 prng(std::time(NULL));
Here's a self-contained version of your code with the various suggestions applied, demonstrating that there is no deadlock/softlock:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/chrono.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <boost/random.hpp>
using boost::this_thread::sleep_for;
using boost::chrono::seconds;
using boost::chrono::milliseconds;
using boost::lexical_cast;
using std::cout;
using std::endl;
struct Upload {
std::string getId() const { return "42"; }
void Wait();
void ReadFileNames();
};
void Upload::ReadFileNames() {
cout << "[DEBUG] ReadFileNames -> A " << endl;
Wait();
cout << "[DEBUG] ReadFileNames -> B " << endl;
// read filename stuff
}
int random_gen(int low, int high) { // not threadsafe
static boost::mt19937 prng(std::time(NULL));
return boost::uniform_int<>(low, high)(prng);
}
void Upload::Wait() {
int const ms_delay = random_gen(1000, 3000);
cout << "RANDOM WAIT TIME = " << ms_delay << endl;
sleep_for(milliseconds(ms_delay));
}
void background(char const* name) {
// desync different background threads
sleep_for(milliseconds(boost::hash_value(name) % 1000));
for (int i=0; i<5; ++i) {
sleep_for(seconds(1));
std::clog << name << " " << i << std::endl;
}
}
void threadAfn() { background("thread A"); }
void threadBfn() { background("thread B"); }
void Uploadfn() {
Upload u;
u.ReadFileNames();
}
int main() {
boost::thread threadA(threadAfn);
boost::thread threadB(threadBfn);
boost::thread Upload(Uploadfn);
threadA.join();
threadB.join();
Upload.join();
}
Prints, e.g.:
[DEBUG] ReadFileNames -> A
RANDOM WAIT TIME = 1150
[DEBUG] ReadFileNames -> B
thread A 0
thread B 0
thread A 1
thread B 1
thread A 2
thread B 2
thread A 3
thread B 3
thread A 4
thread B 4
I have a main program, this main program executes a thread that perform an action until the user triggers a stop. The problem that I have is if I add th.join() the main program won't continue until the thread finishes. And If there is no .join() the program crashs.
#include <iostream>
#include <thread>
#include <optional>
static bool s_finished = false;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
//th1.join();
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording();
std::this_thread::sleep_for(5s);
stopRecording();
return 0;
}
How can I do this?
Joining a thread will cause the program to stop until that thread is finished, and that's why the program blocks. We have to call join() eventually so that all child threads finish before the program exits, but we shouldn't call join until we need the child thread to be finished.
The simplest way to get the program to work is to return the thread from startRecording, so that we have control of it inside main. Then, we join the thread at the end of main, after we call stopRecording.
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
std::thread startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
// (2) We return the thread so we can join it in main:
return th1;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
// (3) We save the thread to a variable named 'worker'
// so we can join it later. I also added an input to startRecording b/c it needed one
std::thread worker = startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
Now, the program prints the expected output, then exits without problems:
Start Program!
[startRecording] Other Task
Working thread: 1
Started thread id: 139985258444544
Working
Working
Working
Working
Working
[stopRecording] Other Task
I marked my changes with (1), (2), (3), and (4) in the comments of the code. They're pretty small, and if you have questions about any of them I can provide additional explanation!
Addendum - using global variables when the signature of startRecording can't be changed
In general, it's best to avoid global variables, but I know it's not always possible to do so. if startRecording's signature can't be changed, we can't return a thread, so the thread has to be accessed globally. Here's how to do that:
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
// (2) we initialize this in startRecording
std::thread worker;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
// (3) worker gets initialized, and thread starts
worker = std::thread(SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
I am following Boost multithreading tutorial here
. Following section 18.13, I try creating a class containing multiple threads as follows:
#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
#include <iostream>
#include <string>
#include <queue>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp>
#include <boost/chrono.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using boost::asio::ip::udp;
using std::cout;
using std::cin;
using std::endl;
using std::string;
using namespace std;
class MultiTask
{
private:
boost::thread_group threads; // thread group
boost::thread* thread_main; // main thread
boost::thread* thread_output; // output thread
boost::thread* thread_input; // input thread
boost::mutex stopMutex;
bool stop;
int i_in, i_out, i_main;
string userInput;
public:
// constructor
MultiTask()
{
thread_main = new boost::thread(boost::ref(*this));
thread_output = new boost::thread(&MultiTask::Callable_Out, this, 1000, boost::ref(i_out));
thread_input = new boost::thread(&MultiTask::Callable_In, this, 1000, boost::ref(i_out), boost::ref(userInput));
//threads.add_thread(thread_main); // main thread = 0 // will throw -> boost thread: trying to join itself
threads.add_thread(thread_output); // output thread = 1
threads.add_thread(thread_input); // input thread = 2
stop = false;
i_in = 0;
i_out = 0;
i_main = 0;
userInput = "";
}
// destructor
~MultiTask()
{
// stop all threads
Stop();
// show exit message
cout << "Exiting MultiTask." << endl;
}
// start the threads
void Start()
{
// Wait till they are finished
threads.join_all();
}
// stop the threads
void Stop()
{
// warning message
cout << "Stopping all threads." << endl;
// signal the threads to stop (thread-safe)
stopMutex.lock();
stop = true;
stopMutex.unlock();
// wait for the threads to finish
threads.interrupt_all();
threads.join_all();
}
void Callable_Out(int interval, int& count)
{
while (1)
{
//cout << "Callable_Out [" << count++ << "]" << endl;
boost::this_thread::sleep(boost::posix_time::millisec(interval));
boost::this_thread::interruption_point();
}
}
void Callable_In(int interval, int& count, string& userInput)
{
while (1)
{
cout << "Callable_In [" << count++ << "]. Enter message: ";
getline(cin, userInput);
boost::this_thread::sleep(boost::posix_time::millisec(interval));
boost::this_thread::interruption_point();
}
}
// Thread function
void operator () ()
{
while (1)
{
//cout << "Main [" << i_main++ << "]." << endl;
//cout << "Main [" << i_main++ << "]. " << userInput << endl;
if (userInput == "STOP")
{
try
{
this->Stop();
}
catch(exception e)
{
cout << e.what() << endl;
}
}
boost::this_thread::sleep(boost::posix_time::millisec(1000));
boost::this_thread::interruption_point();
}
}
};
int main()
{
MultiTask mt;
mt.Start();
}
However, VS throws two of these errors:
Severity Code Description Project File Line Suppression State
Error C2198 'void (__cdecl *)(boost::posix_time::millisec,int &,std::string &)': too few arguments for call mycpp c:\boost_1_66_0\boost\bind\bind.hpp 259
Can someone please help? This is from section 18.13. Also, I do not see where to input the arguments for CallableFunction() in that example. How can it be done in my case? Thanks.
In tutorial CallableFunction function takes only one parameter, it is passed as second parameter in thread constructor new boost::thread(&CallableFunction, i);.
In your case Callable_Out takes 2 parameters, one is missing, you should call
thread_output = new boost::thread(&Callable_Out, boost::posix_time::millisec(0), boost::ref(i_out));
and for Callable_In you call
thread_input = new boost::thread(&Callable_In, boost::posix_time::millisec(1), boost::ref(i_out), boost::ref(userInput));
I'm using a deadline_timer as an asynchronous event and I'm running into a situation where, after some time, the thread waiting on the event never seems to be woken up (despite more calls to cancel()). I've been able to reproduce this using some sample code that I've pasted below; it's not exactly consistent but I have seen what I think is the same issue I'm experiencing.
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);
int num_events = 0;
auto waiter = [&timer, &num_events](boost::asio::yield_context context) {
while (true) {
std::cout << "waiting on event" << std::endl;
boost::system::error_code e;
timer.async_wait(context[e]);
std::cout << "got event (" << e << ")" << std::endl;
++num_events;
}
};
boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (auto i = 0; i < 500000; ++i) {
timer.cancel();
std::cout << i << std::endl;
}
Am I doing something here that's unsupported and inadvertently hitting some race condition? The error code from the wait() never looks troublesome (even on the very last time it's woken up before it never seems to again). EDIT: I've also noticed the original bug on 3 different platforms (Windows, Mac and Linux) but the above test I've been using to reproduce has been on Windows.
The deadline_timer object is not threadsafe.
You're canceling it from another thread than the one that's posting the async_wait. This means the calls can race.
I'm not sure how this can completely inhibit the callback, in your sample. It seems to me that the program should /just/ quit because the tight loop to 500000 finishes quickly (doing many redundant cancels that never get processed, because the coroutine would e.g. not even have posted the new async_wait).
So maybe you mean, "why don't I get 500000 events".
UPDATE
After the comment, here's a trivial transformation that shows how you are gonna be fine calling members on the timer from within an actor. Note: this critically hinges on the idea that the io_service is run from a single thread only!
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <iostream>
using boost::thread;
using boost::asio::io_service;
int main() {
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);
boost::atomic_bool shutdown(false);
int num_events = 0;
auto waiter = [&timer, &num_events, &shutdown](boost::asio::yield_context context) {
while (!shutdown) {
std::cout << "waiting on event" << std::endl;
boost::system::error_code e;
timer.async_wait(context[e]);
std::cout << "got event (" << e.message() << ")" << std::endl;
++num_events;
}
};
boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (auto i = 0; i < 5000; ++i) {
io_service.post([&timer, i]{
std::cout << i << std::endl;
timer.cancel();
});
}
io_service.post([&]{
shutdown = true;
timer.cancel();
});
thread.join();
std::cout << "Check: " << num_events << " events counted\n";
}
Also, it looks like you just wanted to signal a background task. As given you can simplify the program like:
See it Live On Coliru
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
using boost::thread;
using boost::asio::io_service;
int main() {
io_service svc;
int num_events = 0;
auto work = boost::make_shared<io_service::work>(svc); // keep svc running
boost::thread thread(boost::bind(&io_service::run, &svc));
for (auto i = 0; i < 500000; ++i) {
svc.post([&num_events,i]{
std::cout << "got event (" << i << ")" << std::endl;
++num_events;
});
}
work.reset();
thread.join();
std::cout << "Check: " << num_events << " events counted\n";
}
This does print all 500000 events:
got event (0)
got event (1)
got event (3)
...
got event (499998)
got event (499999)
Check: 500000 events counted