feat(util/interrupt): add sleep_for, and simplify request_interrupt

The Lean sleep_for checks the interrupt flag from time to time.

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-11-22 11:32:09 -08:00
parent 935349ec91
commit a776c8b158
6 changed files with 58 additions and 16 deletions

View file

@ -521,10 +521,7 @@ public:
}
void request_interrupt() {
while (!m_thread.request_interrupt()) {
check_interrupted();
std::this_thread::sleep_for(g_small_delay);
}
m_thread.request_interrupt();
}
void write(lua_State * src, int first, int last) {

View file

@ -231,8 +231,7 @@ static void tst5() {
}
});
std::this_thread::sleep_for(dura);
while (!thread.request_interrupt()) {
}
thread.request_interrupt();
thread.join();
#endif
}

View file

@ -239,8 +239,7 @@ static void tst12() {
}
});
std::this_thread::sleep_for(dura);
while (!thread.request_interrupt()) {
}
thread.request_interrupt();
thread.join();
#endif
}

View file

@ -12,6 +12,7 @@ Author: Leonardo de Moura
#include <atomic>
#include "util/debug.h"
#include "util/shared_mutex.h"
#include "util/interrupt.h"
using namespace lean;
void foo() {
@ -124,7 +125,6 @@ static void tst4() {
lean_assert(t2_done);
}
static void tst5() {
shared_mutex mutex;
std::atomic<bool> t2_started(false);
@ -158,10 +158,26 @@ static void tst5() {
t1.join();
t2.join();
}
static void tst6() {
interruptible_thread t1([]() {
try {
// Remark: std::this_thread::sleep_for does not check whether the thread has been interrupted or not.
// std::this_thread::sleep_for(std::chrono::milliseconds(1000000));
sleep_for(1000000);
} catch (interrupted &) {
std::cout << "interrupted...\n";
}
});
sleep_for(20);
t1.request_interrupt();
t1.join();
}
#else
static void tst3() {}
static void tst4() {}
static void tst5() {}
static void tst6() {}
#endif
int main() {
@ -170,5 +186,6 @@ int main() {
tst3();
tst4();
tst5();
tst6();
return has_violations() ? 1 : 0;
}

View file

@ -29,6 +29,19 @@ void check_interrupted() {
}
}
void sleep_for(unsigned ms, unsigned step_ms) {
if (step_ms == 0)
step_ms = 1;
unsigned rounds = ms / step_ms;
std::chrono::milliseconds c(step_ms);
std::chrono::milliseconds r(ms % step_ms);
for (unsigned i = 0; i < rounds; i++) {
std::this_thread::sleep_for(c);
check_interrupted();
}
std::this_thread::sleep_for(r);
}
std::atomic_bool * interruptible_thread::get_flag_addr() {
return &g_interrupt;
}
@ -40,12 +53,16 @@ bool interruptible_thread::interrupted() const {
return f->load();
}
bool interruptible_thread::request_interrupt() {
std::atomic_bool * f = m_flag_addr.load();
if (f == nullptr)
return false;
f->store(true);
return true;
void interruptible_thread::request_interrupt(unsigned try_ms) {
while (true) {
std::atomic_bool * f = m_flag_addr.load();
if (f != nullptr) {
f->store(true);
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(try_ms));
check_interrupted();
}
}
void interruptible_thread::join() {

View file

@ -29,6 +29,15 @@ bool interrupt_requested();
*/
void check_interrupted();
constexpr unsigned g_small_sleep = 50;
/**
\brief Put the current thread to sleep for \c ms milliseconds.
\remark check_interrupted is invoked every \c step_ms milliseconds;
*/
void sleep_for(unsigned ms, unsigned step_ms = g_small_sleep);
/**
\brief Thread that provides a method for setting its interrupt flag.
*/
@ -56,8 +65,12 @@ public:
/**
\brief Send a interrupt request to the current thread. Return
true iff the request has been successfully performed.
\remark The main thread may have to wait the interrupt flag of this thread to
be initialized. If the flag was not initialized, then the main thread will be put
to sleep for \c try_ms milliseconds until it tries to set the flag again.
*/
bool request_interrupt();
void request_interrupt(unsigned try_ms = g_small_sleep);
void join();
bool joinable();