I'm running tbb::parallel_for_each deep within a task_group. The task_group is being canceled and that seems to cause tbb::parallel_for_each to exit without satisfying its postcondition. Here's minimal test case:
tbb::task_group g;
std::vector<int> x { 0, 0, 0, 0 };
std::atomic<std::size_t> counter {0};
g.run([&x, &counter]() {
std::cout << "in run()\n" << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "in run(): slept\n" << std::flush;
assert(tbb::task::self().is_cancelled());
tbb::parallel_for_each(x, [&counter](int& y) {
std::cout << "in run(): in parallel_for_each\n" << std::flush;
++y;
++counter;
});
assert(counter == x.size());
});
std::cout << "canceling\n" << std::flush;
g.cancel();
std::cout << "canceled " << g.is_canceling() << " " << tbb::task::self().is_cancelled() << std::endl;
assert(g.is_canceling());
std::cout << "canceled " << g.is_canceling() << " " << tbb::task::self().is_cancelled() << std::endl;
g.wait();
std::cout << "canceled " << g.is_canceling() << " " << tbb::task::self().is_cancelled() << std::endl;
That is: It has tbb::task_group call run on a function that waits for 0.1 s, then loops over a vector. It counts how many iterations that loop does. It then cancel()s the task group. The output is
canceling
in run()
canceled 1 0
canceled 1 0
in run(): slept
Assertion failed: (counter == x.size()), function operator(), file test.cpp
That's to say that the inner loop never happens. My surprise, though, is that tbb::parallel_for_each is called and exits without exception, but its post-condition (of doing the loop) isn't met!
Is that the expected behavior? The docs don't give any caveats: https://software.intel.com/en-us/node/506160
How do I check for this behavior? Do I always have to check tbb::task::self().is_cancelled() after calling tbb::parallel_for_each if I want to be sure it actually did its job?
Shouldn't tbb::parallel_for_each throw an exception in this case (or at least return bool)?
I can "fix" this by using an isolated context (https://software.intel.com/en-us/node/506075) like this:
tbb::task_group_context root(tbb::task_group_context::isolated);
tbb::parallel_for_each(x, [&counter](int& y) {
std::cout << "in run(): in parallel_for_each\n" << std::flush;
++y;
++counter;
}, root);
but at the moment, I'm not sure when I can ever trust tbb::parallel_for_each to do its job.
Within a task group, calls to tbb::parallel_for_each are subordinate to the task group's context.
Cancelling that task group cancels it, and all subordinate task groups. I cannot find where in the docs "subordinate task group" is defined, but it appears to be groups under the group in the "task tree".
A cancelled tbb::parallel_for_each does not guarantee that all of its iterations are complete. No post condition was violated.
You cancelled the task group, which cancels the subordinate tbb::parallel_for_each's implicit task group, so it doesn't do the operations.
Your isolated context prevents the cancellation from propagating into the parallel for each's task group. You can replicate the effect in that code by canceling root prior to calling parallel_for_each.
Related
I am trying to create a very threaded simple producer consumer toy implementation, but I'm running into a strange issue where the same consumer thread keeps getting rescheduled over and over again even though I am yielding control.
Here is an abridged version of my code. The Main method is simple , I start one producer and two consumer threads. I join to the producer thread and detach the two consumer threads. A getchar at the end of the main method keeps the program from exiting.
std::vector<int> UnprocessedValues;
std::vector<int> ProcessedValues;
std::mutex unprocessed_mutex;
void AddUnprocessedValue()
{
for (int i = 0; i <= 1000; ++i)
{
{
std::lock_guard<std::mutex> guard(unprocessed_mutex);
UnprocessedValues.push_back(i);
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("Unprocessed value added %i \n", UnprocessedValues.back());
}
}
}
void ProcessCurrentValue()
{
while (true)
{
unprocessed_mutex.lock();
if (UnprocessedValues.empty())
{
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("is waiting for values \n");
unprocessed_mutex.unlock();
std::this_thread::yield();
}
else
{
// Process value
unprocessed_mutex.unlock();
}
}
}
I expect that when there are no values present for consumers, they will both yield and end up giving the producer a chance to produce more.
In practice I see a single consumer getting stuck on waiting for values. Eventually the program rights itself, but something is obviously wrong.
If I was seeing the two consumers print that they are waiting in alternate, I would think that somehow the producer is getting shafted by the two consumers taking turns, but the actual result is that the same thread keeps getting rescheduled even though it just yielded.
Finally, when I change the if case from
if (UnprocessedValues.empty())
{
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("is waiting for values \n");
unprocessed_mutex.unlock();
std::this_thread::yield();
}
to
if (UnprocessedValues.empty())
{
unprocessed_mutex.unlock();
std::this_thread::yield();
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("is waiting for values \n");
}
I never see a busy wait. I realize that I could use a condition variable to fix this problem and I have already seen that using a small sleep instead of a yield works. I am just trying to understand why the yield would not work.
I have created this C++17 code that mimics something that I need.
std::cout << "start" << std::endl;
auto a = std::async([]() -> int {
std::this_thread::sleep_for(std::chrono::seconds{ 5 });
return 2;
});
std::cout << a.get() << std::endl;
std::cout << "stop" << std::endl;
The thread sleeps here but in real example I do heavy operations and I return an integer which can be 0, 1 or 7. This is my output:
start
2
stop
This is good! This code will not freeze my UI. I know that a.get() is a blocking operation but is there a way to be non blocking?
In other words: instead of
start
2
stop
can I get as output
start
stop
2
using async? I need async because I have found online that it is useful when return a value is needed. It is also easy to read! I do not want to use std::packaged_task, promises, futures etc because async is easy.
If it cannot be non blocking can I use something else?
This code will output what you need:
std::cout << "start" << std::endl;
std::thread{
[]() {
auto a = std::async([]() -> int {
std::this_thread::sleep_for(std::chrono::seconds{ 5 });
return 2;
});
std::cout << a.get() << std::endl;
}
}.detach();
std::cout << "stop" << std::endl;
If I were you I wouldn't use async at all. If you just need to display a value and you don't want to block, you should do something else. For example:
std::cout << "start" << std::endl;
std::thread{
[]() {
//do here what you need and print the result
}
}.detach();
/* ... or ...
auto t = std::thread{ ... };
t.detach();
*/
std::cout << "stop" << std::endl;
See that detach() makes the new thread "independent" and doesn't block while join() blocks. The point is that async must block because if it has to do an operation that takes a lot of time, it has to spend that time!
According to my knowledge and as far as I checked the boost::asio documentation and source code there is no way to destroy explicitly all pending handlers on a given io_context aside from destroying the context itself?
I need to be able, if possible, to stop the io_context, destroy the pending handlers on the io_context, then do some other things and finally destroy all io objects (timers, pipes, etc) associated with the given io_context and the io_context itself.
I know that I can use work_guard::reset and let all pending handlers to run and then the io_context will stop by itself, but the problem is that many of the handlers may produce (post/defer/etc) new pending handlers, etc i.e. each such handler will need to be guarded with something like 'if stopped'.
I think that the io_context::shutdown does exactly this but there is no way, aside from inheritance maybe, to call explicitly the shutdown function because it's not public.
Thanks.
Trying your suggestion using the protected shutdown results in a segfault on my system. I think it's protected for a reason :)
Anyhow, it looks like a judicious combination of restart/stop/reset might do the job. It's weird that some of the handler queue apparently stays around UNLESS one does a (empty) run/run_one. In fact even a poll_one seems to suffice. So, by all means, include that.
Here's my test bed code, you might find it useful:
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;
struct Handler {
void operator()(boost::system::error_code ec) { std::cout << "Handler invoked: " << ec.message() << std::endl; }
struct Instance { // logging only unique instance to avoid noise of moved handlers
Instance() { std::cout << "Created handler instance" << std::endl; }
~Instance() { std::cout << "Destroyed handler instance" << std::endl; }
};
std::unique_ptr<Instance> _instance = std::make_unique<Instance>();
};
int main()
{
struct Hack : boost::asio::io_context {
using boost::asio::io_context::shutdown;
} io;
auto work = make_work_guard(io);
std::cout << " -- run" << std::endl;
auto t = std::thread([&]{ io.run(); });
{
boost::asio::high_resolution_timer tim(io, 2s);
tim.async_wait(Handler{});
work.reset(); // no longer needed
std::this_thread::sleep_for(500ms);
#if 1
io.stop();
#else
io.shutdown(); // segfaults
#endif
}
std::cout << " -- timer destructed" << std::endl;
std::cout << " -- joining" << std::endl;
t.join();
std::cout << " -- empy run to flush handler queue" << std::endl;
io.reset();
//io.run();
//io.run_one();
io.poll_one();
std::cout << " -- bye" << std::endl;
}
Prints
-- run
Created handler instance
-- timer destructed
-- joining
-- empy run to flush handler queue
Handler invoked: Operation canceled
Destroyed handler instance
-- bye
UPDATE
Here's my best suggestion (apart from, I guess, not sharing io at all):
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;
struct Handler {
void operator()(boost::system::error_code ec) { std::cout << "Handler invoked: " << ec.message() << std::endl; }
struct Instance { // logging only unique instance to avoid noise of moved handlers
Instance() { std::cout << "Created handler instance" << std::endl; }
~Instance() { std::cout << "Destroyed handler instance" << std::endl; }
};
std::unique_ptr<Instance> _instance = std::make_unique<Instance>();
};
int main()
{
std::unique_ptr<boost::asio::io_context> io;
int i = 1;
for (auto delay : { 1500ms, 500ms }) {
std::cout << " ------------------- reinitialized -------------- \n";
io = std::make_unique<boost::asio::io_context>();
boost::asio::high_resolution_timer tim(*io, 1s);
std::cout << i << " -- run" << std::endl;
auto t = std::thread([&]{ io->run(); });
tim.async_wait(Handler{});
std::this_thread::sleep_for(delay);
std::cout << i << " -- stop" << std::endl;
io->stop();
std::cout << i << " -- joining" << std::endl;
t.join();
std::cout << " ------------------- destruct ------------------- \n";
io.reset();
}
std::cout << "Bye" << std::endl;
}
Prints
------------------- reinitialized --------------
1 -- run
Created handler instance
Handler invoked: Success
Destroyed handler instance
1 -- stop
1 -- joining
------------------- destruct -------------------
------------------- reinitialized --------------
1 -- run
Created handler instance
1 -- stop
1 -- joining
------------------- destruct -------------------
Destroyed handler instance
Bye
I am seeing unusual signal numbers (for example 50, 80 or 117) from the following code when waiting for a child process to terminate. I am only seeing this from one particular child process, and I have no access to the process source code and it only happens some of the time.
I want to know what these unusual values mean, given NSIG == 32, and where I can find some documentation in the headers or man pages?
Note that this code runs in a loop sending progressively more menacing signals until the child terminates.
int status, signal;
if (waitpid(m_procId, &status, WNOHANG) < 0) {
LOGERR << "Failed to wait for process " << name() << ": " <<
strerror(errno) << " (" << errno << ")";
break;
} else if (WIFEXITED(status)) {
m_exitCode = WEXITSTATUS(status);
terminated = true;
LOGINF << "Process " << name() << " terminated with exit code " << m_exitCode;
} else if (WIFSIGNALED(status)) {
signal = WTERMSIG(status); // !!! signal is sometimes 50, 80 or 117 !!!
terminated = true;
LOGINF << "Process " << name() << " terminated by signal " << signal;
} else {
LOGWRN << "Process " << name() << " changed state but did not terminate. status=0x" <<
hex << status;
}
This is running under OSX 10.8.4, but I have also seen it in 10.9 GM seed.
EDIT Modifying the code as below makes the code more robust, however sometimes the child process gets orphaned as I guess the loop doesn't do enough to kill the child process.
else if (WIFSIGNALED(status)) {
signal = WTERMSIG(status);
if (signal < NSIG) {
terminated = true;
LOGINF << "Process " << name() << " terminated by signal " << signal;
} else {
LOGWRN << "Process " << name() << " produced unusual signal " << signal
<< "; assuming it's not terminated";
}
}
Note this code is part of the Process::unload() method of this class.
From the OS X manpage for waitpid, when specifing WNOHANG, you should check for a return of 0:
When the WNOHANG option is specified and no processes wish to report status, wait4() returns a process
id of 0.
The waitpid() call is identical to wait4() with an rusage value of zero. The older wait3() call is the
same as wait4() with a pid value of -1.
The code posted does not check for this, which suggests to me that the value of status is likely junk (the value of the int is never initialized). This could cause what you are seeing.
EDIT: status is indeed only set when waitpid returns > 0.
I have blocking task which will be performed by find_the_question() function. However, I do not want thread executing this function take more than 10 seconds. So in case it takes more than 10 seconds, I want to close that thread with cleaning all the resources.
I tried to write a code for that, but somehow I am not able to get a interrupt in find_the_question() function if thread takes more than 10 seconds. Could you please tell me what am I doing wrong?
void find_the_question(std::string value)
{
//allocate x resources
try{
//do some process on resources
sleep(14);
//clean resources
}
catch(boost::thread_interrupted const& )
{
//clean resources
std::cout << "Worker thread interrupted" << std::endl;
}
}
int main()
{
boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(10000);
std::cout << "In main" << std::endl;
boost::thread t1(find_the_question, "Can you block me");
t1.interrupt();
if (t1.timed_join(timeout))
{
//finished
std::cout << "Worker thread finished" << std::endl;
}
else
{
//Not finished;
std::cout << "Worker thread not finished" << std::endl;
}
std::cout << "In main end" << std::endl;
}
Output:
If t1 takes more than 10 seconds to complete, I am getting following console output.
std::cout << "In main" << std::endl;
std::cout << "Worker thread not finished" << std::endl;
std::cout << "In main end" << std::endl;
whereas, I am expecting following output
std::cout << "In main" << std::endl;
std::cout << "Worker thread interrupted" << std::endl;
std::cout << "Worker thread not finished" << std::endl;
std::cout << "In main end" << std::endl;
Could you please tell me what am I doing wrong.
Thanks in advance
For using boost::thread::interrupt(), you have to use boost::thread::sleep() for it to work.
A running thread can be interrupted by invoking the interrupt() member
function of the corresponding boost::thread object. When the
interrupted thread next executes one of the specified interruption
points (or if it is currently blocked whilst executing one) with
interruption enabled, then a boost::thread_interrupted exception will
be thrown in the interrupted thread. If not caught, this will cause
the execution of the interrupted thread to terminate. As with any
other exception, the stack will be unwound, and destructors for
objects of automatic storage duration will be executed
Predefined interruption points:
The following functions are interruption points, which will throw
boost::thread_interrupted if interruption is enabled for the current
thread, and interruption is requested for the current thread:
boost::thread::join()
boost::thread::timed_join()
boost::condition_variable::wait()
boost::condition_variable::timed_wait()
boost::condition_variable_any::wait()
boost::condition_variable_any::timed_wait()
boost::thread::sleep()
boost::this_thread::sleep()
boost::this_thread::interruption_point()