Skip to content

Commit 741e748

Browse files
committed
Restoring TestThread code with added std::lock_guard<std::mutex>.
1 parent eec595b commit 741e748

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

tests/test_iostream.cpp

+47
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
#include <pybind11/iostream.h>
1515
#include "pybind11_tests.h"
16+
#include <atomic>
1617
#include <iostream>
18+
#include <mutex>
1719
#include <string>
20+
#include <thread>
1821

1922

2023
void noisy_function(std::string msg, bool flush) {
@@ -29,6 +32,44 @@ void noisy_funct_dual(std::string msg, std::string emsg) {
2932
std::cerr << emsg;
3033
}
3134

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+
3273
TEST_SUBMODULE(iostream, m) {
3374

3475
add_ostream_redirect(m);
@@ -74,4 +115,10 @@ TEST_SUBMODULE(iostream, m) {
74115
std::cout << msg << std::flush;
75116
std::cerr << emsg << std::flush;
76117
});
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);
77124
}

tests/test_iostream.py

+23
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,26 @@ def test_redirect_both(capfd):
306306
assert stderr == ""
307307
assert stream.getvalue() == msg
308308
assert stream2.getvalue() == msg2
309+
310+
311+
def test_threading():
312+
with m.ostream_redirect(stdout=True, stderr=False):
313+
# start some threads
314+
threads = []
315+
316+
# start some threads
317+
for _j in range(20):
318+
threads.append(m.TestThread())
319+
320+
# give the threads some time to fail
321+
threads[0].sleep()
322+
323+
# stop all the threads
324+
for t in threads:
325+
t.stop()
326+
327+
for t in threads:
328+
t.join()
329+
330+
# if a thread segfaults, we don't get here
331+
assert True

0 commit comments

Comments
 (0)