| #include <condition_variable> |
| #include <iostream> |
| #include <mutex> |
| #include <thread> |
| |
| std::mutex mtx; |
| std::condition_variable cv; |
| int ready_thread_id = 0; |
| int signal_main_thread = 0; |
| |
| void worker(int id) { |
| std::cout << "Worker " << id << " executing..." << std::endl; |
| |
| // lldb test should change signal_main_thread to true to break the loop. |
| while (!signal_main_thread) { |
| std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| } |
| |
| // Signal the main thread to continue main thread |
| { |
| std::lock_guard<std::mutex> lock(mtx); |
| ready_thread_id = id; // break worker thread here |
| } |
| cv.notify_one(); |
| |
| std::this_thread::sleep_for(std::chrono::seconds(1)); |
| std::cout << "Worker " << id << " finished." << std::endl; |
| } |
| |
| void deadlock_func(std::unique_lock<std::mutex> &lock) { |
| int i = 10; |
| ++i; // Set interrupt breakpoint here |
| printf("%d", i); // Finish step-over from inner breakpoint |
| auto func = [] { return ready_thread_id == 1; }; |
| cv.wait(lock, func); |
| } |
| |
| int simulate_thread() { |
| std::thread t1(worker, 1); |
| |
| std::unique_lock<std::mutex> lock(mtx); |
| deadlock_func(lock); // Set breakpoint1 here |
| |
| std::thread t2(worker, 2); // Finish step-over from breakpoint1 |
| |
| cv.wait(lock, [] { return ready_thread_id == 2; }); |
| |
| t1.join(); |
| t2.join(); |
| |
| std::cout << "Main thread continues..." << std::endl; |
| |
| return 0; |
| } |
| |
| int bar() { return 54; } |
| |
| int foo(const std::string p1, int extra) { return p1.size() + extra; } |
| |
| int main(int argc, char *argv[]) { |
| std::string ss = "this is a string for testing", |
| ls = "this is a long string for testing"; |
| foo(ss.size() % 2 == 0 ? ss : ls, bar()); // Set breakpoint2 here |
| |
| simulate_thread(); // Finish step-over from breakpoint2 |
| |
| return 0; |
| } |