-
Notifications
You must be signed in to change notification settings - Fork 365
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Isolate interrupt requests to single thread
- Loading branch information
Showing
3 changed files
with
153 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// tut | ||
#include <tut/tut.hpp> | ||
// geos | ||
#include <geos/util/Interrupt.h> | ||
// std | ||
#include <chrono> | ||
#include <thread> | ||
|
||
using geos::util::Interrupt; | ||
|
||
namespace tut { | ||
// | ||
// Test Group | ||
// | ||
|
||
// Common data used in test cases. | ||
struct test_interrupt_data { | ||
static void workForever() { | ||
try { | ||
std::cerr << "Started " << std::this_thread::get_id() << "." << std::endl; | ||
while (true) { | ||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||
GEOS_CHECK_FOR_INTERRUPTS(); | ||
} | ||
} catch (const std::exception&) { | ||
std::cerr << "Interrupted " << std::this_thread::get_id() << "." << std::endl; | ||
return; | ||
} | ||
} | ||
|
||
static void interruptNow() { | ||
Interrupt::request(); | ||
} | ||
|
||
static std::map<std::thread::id, bool>* toInterrupt; | ||
|
||
static void interruptIfRequested() { | ||
if (toInterrupt == nullptr) { | ||
return; | ||
} | ||
|
||
auto it = toInterrupt->find(std::this_thread::get_id()); | ||
if (it != toInterrupt->end() && it->second) { | ||
it->second = false; | ||
Interrupt::request(); | ||
} | ||
} | ||
}; | ||
|
||
std::map<std::thread::id, bool>* test_interrupt_data::toInterrupt = nullptr; | ||
|
||
typedef test_group<test_interrupt_data> group; | ||
typedef group::object object; | ||
|
||
group test_interrupt_group("geos::util::Interrupt"); | ||
|
||
// | ||
// Test Cases | ||
// | ||
|
||
|
||
// Interrupt worker thread via global request from from main thead | ||
// No longer works, because Interrupt::request now interrupts only the thread that calls it. | ||
#if 0 | ||
template<> | ||
template<> | ||
void object::test<1> | ||
() | ||
{ | ||
std::thread t(workForever); | ||
Interrupt::request(); | ||
|
||
t.join(); | ||
} | ||
#endif | ||
|
||
// Interrupt worker thread via global requset from worker thread using a callback | ||
template<> | ||
template<> | ||
void object::test<2> | ||
() | ||
{ | ||
Interrupt::registerCallback(interruptIfRequested); | ||
|
||
std::thread t1(workForever); | ||
std::thread t2(workForever); | ||
|
||
std::map<std::thread::id, bool> shouldInterrupt; | ||
shouldInterrupt[t1.get_id()] = false; | ||
shouldInterrupt[t2.get_id()] = false; | ||
toInterrupt = &shouldInterrupt; | ||
|
||
shouldInterrupt[t2.get_id()] = true; | ||
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); | ||
shouldInterrupt[t1.get_id()] = true; | ||
|
||
t1.join(); | ||
t2.join(); | ||
} | ||
|
||
} // namespace tut | ||
|