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