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:
parent
935349ec91
commit
a776c8b158
6 changed files with 58 additions and 16 deletions
|
@ -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) {
|
||||
|
|
|
@ -231,8 +231,7 @@ static void tst5() {
|
|||
}
|
||||
});
|
||||
std::this_thread::sleep_for(dura);
|
||||
while (!thread.request_interrupt()) {
|
||||
}
|
||||
thread.request_interrupt();
|
||||
thread.join();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -239,8 +239,7 @@ static void tst12() {
|
|||
}
|
||||
});
|
||||
std::this_thread::sleep_for(dura);
|
||||
while (!thread.request_interrupt()) {
|
||||
}
|
||||
thread.request_interrupt();
|
||||
thread.join();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue