面试题
近期有之前同事出去面试,面试问到了一道多线程的问题,深入思考之后觉得值得研究一下,特此记录如下:
面试问题:
创建三个线程A,B,C ,要求让这三个线程顺次执行,也就是
A
⇒
\Rightarrow
⇒ B
⇒
\Rightarrow
⇒ C
⇒
\Rightarrow
⇒ A
⇒
\Rightarrow
⇒ B
⇒
\Rightarrow
⇒ C 这样执行
实现方法
使用单个条件变量实现
使用一个全局变量 current_thread 记录当前要执行的 Thread 的 index,创建三个线程 A,B,C,对应的 index 分别为 1,2,3 (使用传参的方式传入到执行函数中),在执行函数中,只有当线程的 index 和 current_thread 相匹配的时候,才会执行对应的代码,否则使用 condition_variable 的 wait 函数使线程进入阻塞等待状态
对应代码如下:
mutex mtx;
condition_variable cv;
int current_thread = 1;
void threadFunction(int thread_num) {
loop:
{
unique_lock<mutex> lock(mtx);
while (current_thread != thread_num) {
cv.wait(lock);
}
// 执行线程操作
std::cout << "Thread " << thread_num << " is running." << std::endl;
this_thread::sleep_for(chrono::milliseconds(1000));
// 更新 current_thread,唤醒下一个线程
++current_thread;
if (current_thread == 4) {
current_thread = 1;
}
cv.notify_all();
goto loop;
}
}
{
thread t1(threadFunction, 1);
thread t2(threadFunction, 2);
thread t3(threadFunction, 3);
t1.join();
t2.join();
t3.join();
}
因为 condition_variable 自带一个 mutex 保护,所以全局变量 current_thread 不必要再加另外的锁保护
使用三个条件变量实现
使用三个条件变量的方法比较直观,创建三个线程 thread A,B,C,在A 中使用 condition_variable1 唤醒 B,在 B 中使用 condition_variable2 唤醒 C,在 C 中再使用condition_variable3 唤醒A,周而复始,实现代码如下:
注意代码中使用了 goto 语句用于循环,本质上使用 while 语句也是一样的
condition_variable cv3;
condition_variable cv1;
condition_variable cv2;
mutex mtx1;
mutex mtx2;
mutex mtx3;
void threadFunction1(int thread_num) {
unique_lock<mutex> lock(mtx1);
loop:
cv1.wait(lock);
std::cout << "Thread1 running." << std::endl;
this_thread::sleep_for(chrono::milliseconds(1000));
cv2.notify_all();
goto loop;
}
void threadFunction2(int thread_num) {
unique_lock<mutex> lock(mtx2);
loop:
cv2.wait(lock);
std::cout << "Thread2 running." << std::endl;
this_thread::sleep_for(chrono::milliseconds(1000));
cv3.notify_all();
goto loop;
}
void threadFunction3(int thread_num) {
unique_lock<mutex> lock(mtx3);
loop:
cv3.wait(lock);
std::cout << "Thread3 running." << std::endl;
this_thread::sleep_for(chrono::milliseconds(1000));
cv1.notify_all();
goto loop;
}
{
thread t1(threadFunction1, 1);
thread t2(threadFunction2, 2);
thread t3(threadFunction3, 3);
cv1.notify_all();
t1.join();
t2.join();
t3.join();
}