Change std::thread execution flow with signals in c++

I have a program starting an std::thread doing the following: sleep X, execute a function, terminate.

create std::thread(Xms, &func)
  wait Xms
  then do func()
  end

I was wondering if I could for example send a signal to my std::thread in order to instantly break the sleep and do func, then quit.

Do I need to send the signal to std::thread::id in order to perform this?

my thread is launched this way, with a lambda function:

template<typename T, typename U>
void                          execAfter(T func, U params, const int ms)
{
  std::thread                 thread([=](){
      std::this_thread::sleep_for(std::chrono::milliseconds(ms));
      func(params);
    });
  thread.detach();
}

Using wait_for of std::condition_variable would be the way to go, if the thread model can't be changed. In the code snippet below, the use of the condition_variable is wrapped into a class of which objects have to be shared across the threads.

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>

class BlockCondition
{
    private:
        mutable std::mutex m;
        std::atomic<bool> done;
        mutable std::condition_variable cv;
    public:
        BlockCondition()
        :
           m(),
           done(false),
           cv()
        {
        }
        void wait_for(int duration_ms)
        {
            std::unique_lock<std::mutex> l(m);
            int ms_waited(0);
            while ( !done.load() && ms_waited < duration_ms )
            {
               auto t_0(std::chrono::high_resolution_clock::now());
               cv.wait_for(l, std::chrono::milliseconds(duration_ms - ms_waited));
               auto t_1(std::chrono::high_resolution_clock::now());
               ms_waited += std::chrono::duration_cast<std::chrono::milliseconds>(t_1 - t_0).count();
            }
        }
        void release()
        {
            std::lock_guard<std::mutex> l(m);
            done.store(true);
            cv.notify_one();
        }
};

void delayed_func(BlockCondition* block)
{
    block->wait_for(1000);
    std::cout << "Hello actual workn";
}

void abortSleepyFunction(BlockCondition* block)
{
    block->release();
}

void test_aborted()
{
    BlockCondition b();
    std::thread delayed_thread(delayed_func, &b);
    abortSleepyFunction(&b);
    delayed_thread.join();
}

void test_unaborted()
{
    BlockCondition b();
    std::thread delayed_thread(delayed_func, &b);
    delayed_thread.join();
}

int main()
{
    test_aborted();
    test_unaborted();
}

Note that there might be spurious wakeups that abort the wait call prematurely. To account for that, we count the milliseconds actually waited and continue waiting until the done flag is set.


As was pointed out in the comments, this wasn't the smartest approach for solving your problem in the first place. As implementing a proper interruption mechanism is quite complex and extremely easy to get wrong, here are suggestions for a workaround:

Instead of sleeping for the whole timeout, simply loop over a sleep of fixed small size (eg 10 milliseconds) until the desired duration has elapsed. After each sleep you check an atomic flag whether interruption was requested. This is a dirty solution, but is the quickest to pull of.

Alternatively, supply each thread with a condition_variable and do a wait on it instead of doing the this_thread::sleep . Notify the condition variable to indicate the request for interruption. You will probably still want an additional flag to protect against spurious wakeups so you don't accidentally return too early.


Ok, to figure this out I found a new implementation, it's inspired by all your answers so thanks a lot.

First I am gonna do a BombHandler item, in the main Game item. It will have a an attribute containing all the Bomb items.

This BombHandler will be a singleton, containing a timerLoop() function who will execute in a thread (This way I only use ONE thread for xxx bombs, way more effective)

The timerLoop() will usleep(50) then pass through the whole std::list elements and call Bomb::incrTimer() who will increment their internal _timer attribute by 10ms indefinitely, and check bombs who have to explode.

When they reach 2000ms for instance, BombHandler.explode() will be called, exploding the bomb and deleting it.

If another bomb is in range Bomb::touchByFire() will be called, and set the internal attribute of Bomb, _timer, to TIME_TO_EXPLODE (1950ms).

Then it will be explode 50ms later by BombHandler::explode().

Isn't this a nice solution?

Again, thanks for your answers! Hope this can help.

链接地址: http://www.djcxy.com/p/5204.html

上一篇: Windows setevent处理

下一篇: 用c ++中的信号改变std :: thread的执行流程