Skip to content

Commit 883ac69

Browse files
committed
test: add comprehensive comments for the tests
1 parent ad4203f commit 883ac69

File tree

1 file changed

+71
-7
lines changed

1 file changed

+71
-7
lines changed

tests/test_scoped_critical_section.cpp

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class BoolWrapper {
3636
void set(bool value) { value_.store(value, std::memory_order_release); }
3737

3838
private:
39-
std::atomic<bool> value_{false};
39+
std::atomic_bool value_{false};
4040
};
4141

4242
#if defined(PYBIND11_HAS_BARRIER)
@@ -47,22 +47,40 @@ void test_scoped_critical_section(const py::handle &cls) {
4747
bool output = false;
4848

4949
{
50+
// Release the GIL to allow run threads in parallel.
5051
py::gil_scoped_release gil_release{};
5152

5253
std::thread t1([&]() {
54+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
55+
// before entering the critical section. Otherwise, the critical section
56+
// will cause a segmentation fault.
5357
py::gil_scoped_acquire ensure_tstate{};
58+
// Enter the critical section with the same object as the second thread.
5459
py::scoped_critical_section lock{bool_wrapper};
60+
// At this point, the object is locked by this thread via the scoped_critical_section.
61+
// This barrier will ensure that the second thread waits until this thread has released
62+
// the critical section before proceeding.
5563
barrier.arrive_and_wait();
56-
auto *bw = bool_wrapper.cast<BoolWrapper *>();
64+
// Sleep for a short time to simulate some work in the critical section.
65+
// This sleep is necessary to test the locking mechanism properly.
5766
std::this_thread::sleep_for(std::chrono::milliseconds(10));
67+
auto *bw = bool_wrapper.cast<BoolWrapper *>();
5868
bw->set(true);
5969
});
6070

6171
std::thread t2([&]() {
72+
// This thread will wait until the first thread has entered the critical section due to
73+
// the barrier.
6274
barrier.arrive_and_wait();
6375
{
76+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
77+
// before entering the critical section. Otherwise, the critical section
78+
// will cause a segmentation fault.
6479
py::gil_scoped_acquire ensure_tstate{};
80+
// Enter the critical section with the same object as the first thread.
6581
py::scoped_critical_section lock{bool_wrapper};
82+
// At this point, the critical section is released by the first thread, the value
83+
// is set to true.
6684
auto *bw = bool_wrapper.cast<BoolWrapper *>();
6785
output = bw->get();
6886
}
@@ -84,12 +102,23 @@ void test_scoped_critical_section2(const py::handle &cls) {
84102
std::pair<bool, bool> output{false, false};
85103

86104
{
105+
// Release the GIL to allow run threads in parallel.
87106
py::gil_scoped_release gil_release{};
88107

89108
std::thread t1([&]() {
109+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
110+
// before entering the critical section. Otherwise, the critical section
111+
// will cause a segmentation fault.
90112
py::gil_scoped_acquire ensure_tstate{};
113+
// Enter the critical section with two different objects.
114+
// This will ensure that the critical section is locked for both objects.
91115
py::scoped_critical_section lock{bool_wrapper1, bool_wrapper2};
116+
// At this point, objects is locked by this thread via the scoped_critical_section.
117+
// This barrier will ensure that other threads wait until this thread has released
118+
// the critical section before proceeding.
92119
barrier.arrive_and_wait();
120+
// Sleep for a short time to simulate some work in the critical section.
121+
// This sleep is necessary to test the locking mechanism properly.
93122
std::this_thread::sleep_for(std::chrono::milliseconds(10));
94123
auto *bw1 = bool_wrapper1.cast<BoolWrapper *>();
95124
auto *bw2 = bool_wrapper2.cast<BoolWrapper *>();
@@ -98,20 +127,36 @@ void test_scoped_critical_section2(const py::handle &cls) {
98127
});
99128

100129
std::thread t2([&]() {
130+
// This thread will wait until the first thread has entered the critical section due to
131+
// the barrier.
101132
barrier.arrive_and_wait();
102133
{
134+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
135+
// before entering the critical section. Otherwise, the critical section
136+
// will cause a segmentation fault.
103137
py::gil_scoped_acquire ensure_tstate{};
138+
// Enter the critical section with the same object as the first thread.
104139
py::scoped_critical_section lock{bool_wrapper1};
140+
// At this point, the critical section is released by the first thread, the value
141+
// is set to true.
105142
auto *bw1 = bool_wrapper1.cast<BoolWrapper *>();
106143
output.first = bw1->get();
107144
}
108145
});
109146

110147
std::thread t3([&]() {
148+
// This thread will wait until the first thread has entered the critical section due to
149+
// the barrier.
111150
barrier.arrive_and_wait();
112151
{
152+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
153+
// before entering the critical section. Otherwise, the critical section
154+
// will cause a segmentation fault.
113155
py::gil_scoped_acquire ensure_tstate{};
156+
// Enter the critical section with the same object as the first thread.
114157
py::scoped_critical_section lock{bool_wrapper2};
158+
// At this point, the critical section is released by the first thread, the value
159+
// is set to true.
115160
auto *bw2 = bool_wrapper2.cast<BoolWrapper *>();
116161
output.second = bw2->get();
117162
}
@@ -134,22 +179,40 @@ void test_scoped_critical_section2_same_object_no_deadlock(const py::handle &cls
134179
bool output = false;
135180

136181
{
182+
// Release the GIL to allow run threads in parallel.
137183
py::gil_scoped_release gil_release{};
138184

139185
std::thread t1([&]() {
186+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
187+
// before entering the critical section. Otherwise, the critical section
188+
// will cause a segmentation fault.
140189
py::gil_scoped_acquire ensure_tstate{};
141-
py::scoped_critical_section lock{bool_wrapper, bool_wrapper};
190+
// Enter the critical section with the same object as the second thread.
191+
py::scoped_critical_section lock{bool_wrapper, bool_wrapper}; // same object used here
192+
// At this point, the object is locked by this thread via the scoped_critical_section.
193+
// This barrier will ensure that the second thread waits until this thread has released
194+
// the critical section before proceeding.
142195
barrier.arrive_and_wait();
196+
// Sleep for a short time to simulate some work in the critical section.
197+
// This sleep is necessary to test the locking mechanism properly.
143198
std::this_thread::sleep_for(std::chrono::milliseconds(10));
144199
auto *bw = bool_wrapper.cast<BoolWrapper *>();
145200
bw->set(true);
146201
});
147202

148203
std::thread t2([&]() {
204+
// This thread will wait until the first thread has entered the critical section due to
205+
// the barrier.
149206
barrier.arrive_and_wait();
150207
{
208+
// Use gil_scoped_acquire to ensure we have a valid Python thread state
209+
// before entering the critical section. Otherwise, the critical section
210+
// will cause a segmentation fault.
151211
py::gil_scoped_acquire ensure_tstate{};
212+
// Enter the critical section with the same object as the first thread.
152213
py::scoped_critical_section lock{bool_wrapper};
214+
// At this point, the critical section is released by the first thread, the value
215+
// is set to true.
153216
auto *bw = bool_wrapper.cast<BoolWrapper *>();
154217
output = bw->get();
155218
}
@@ -190,8 +253,12 @@ TEST_SUBMODULE(scoped_critical_section, m) {
190253
auto BoolWrapperHandle = py::handle(BoolWrapperClass);
191254
(void) BoolWrapperHandle.ptr(); // suppress unused variable warning
192255

256+
m.attr("has_barrier") =
193257
#ifdef PYBIND11_HAS_BARRIER
194-
m.attr("has_barrier") = true;
258+
true;
259+
#else
260+
false;
261+
#endif
195262

196263
m.def("test_scoped_critical_section",
197264
[BoolWrapperHandle]() -> void { test_scoped_critical_section(BoolWrapperHandle); });
@@ -200,7 +267,4 @@ TEST_SUBMODULE(scoped_critical_section, m) {
200267
m.def("test_scoped_critical_section2_same_object_no_deadlock", [BoolWrapperHandle]() -> void {
201268
test_scoped_critical_section2_same_object_no_deadlock(BoolWrapperHandle);
202269
});
203-
#else
204-
m.attr("has_barrier") = false;
205-
#endif
206270
}

0 commit comments

Comments
 (0)