13
13
14
14
#include < pybind11/iostream.h>
15
15
#include " pybind11_tests.h"
16
+ #include < atomic>
16
17
#include < iostream>
18
+ #include < mutex>
17
19
#include < string>
20
+ #include < thread>
18
21
19
22
void noisy_function (const std::string &msg, bool flush) {
20
23
@@ -28,6 +31,44 @@ void noisy_funct_dual(const std::string &msg, const std::string &emsg) {
28
31
std::cerr << emsg;
29
32
}
30
33
34
+ // object to manage C++ thread
35
+ // simply repeatedly write to std::cerr until stopped
36
+ // redirect is called at some point to test the safety of scoped_estream_redirect
37
+ struct TestThread {
38
+ TestThread () : t_{nullptr }, stop_{false } {
39
+ auto thread_f = [this ] {
40
+ static std::mutex cout_mutex;
41
+ while (!stop_) {
42
+ {
43
+ const std::lock_guard<std::mutex> lock (cout_mutex);
44
+ std::cout << " x" << std::flush;
45
+ }
46
+ std::this_thread::sleep_for (std::chrono::microseconds (50 ));
47
+ } };
48
+ t_ = new std::thread (std::move (thread_f));
49
+ }
50
+
51
+ ~TestThread () {
52
+ delete t_;
53
+ }
54
+
55
+ void stop () { stop_ = true ; }
56
+
57
+ void join () {
58
+ py::gil_scoped_release gil_lock;
59
+ t_->join ();
60
+ }
61
+
62
+ void sleep () {
63
+ py::gil_scoped_release gil_lock;
64
+ std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
65
+ }
66
+
67
+ std::thread * t_;
68
+ std::atomic<bool > stop_;
69
+ };
70
+
71
+
31
72
TEST_SUBMODULE (iostream, m) {
32
73
33
74
add_ostream_redirect (m);
@@ -69,4 +110,10 @@ TEST_SUBMODULE(iostream, m) {
69
110
std::cout << msg << std::flush;
70
111
std::cerr << emsg << std::flush;
71
112
});
113
+
114
+ py::class_<TestThread>(m, " TestThread" )
115
+ .def (py::init<>())
116
+ .def (" stop" , &TestThread::stop)
117
+ .def (" join" , &TestThread::join)
118
+ .def (" sleep" , &TestThread::sleep );
72
119
}
0 commit comments