昨天面了个大厂,自己太傻逼了,这么简单的一道题目没写出来。因为我不太熟悉条件变量,拖了很长时间,面试官估计有点失望,后续的八股也没问什么,意料之中的挂了😭。
还有个题目是LRU,这个倒是临时抱佛脚复习到了,写出来了。
题目
问题:线程1打印1,线程2打印2,线程3打印3,线程1打印4,线程2打印5,线程3打印6……一直打印到100。
其实一点都不难,就是我自己平时压根没做过多少线程同步的练习,对于条件变量之类的玩意基本停留在理论和学习时的简单demo层面,一上战场加上紧张就毛都不会了。
思路1-直接用线程序号做判断
最简单的一个思路,因为只有三个线程,每个线程打印的数字是有规律的
- 线程一打印的数字%3都等于1
- 线程二打印的数字%3都等于2
- 线程三打印的数字%3都等于0
所以我们可以直接写一个函数,提供一个线程编号,通过计算判断当前是否是自己需要打印的数字,不是就睡觉。这个方法是最简单的,只需要一个全局变量加一个锁就能实现。
两个atomic变量,一个用于主线程通知所有线程当前已经初始化完毕,另外一个用于线程通知主线程当前已经执行完毕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include <thread> #include <mutex> #include <atomic> #include <iostream>
std::atomic<bool> isRun = false; std::atomic<bool> isFinished = false; std::mutex gMtx; int count = 1;
void PrintCountFun(int no) { while(!isRun) { std::this_thread::sleep_for(std::chrono::microseconds(10)); }
while(!isFinished) { gMtx.lock(); if(count > 100) { isFinished = true; gMtx.unlock(); return; } if(no!=3 && count % 3 == no) { std::cout << no << " - " << std::this_thread::get_id() << " - c: " << count << std::endl; count ++; gMtx.unlock(); continue; } if(no == 3 && count % 3 == 0) { std::cout << no << " - " << std::this_thread::get_id() << " - c: " << count << std::endl; count ++; gMtx.unlock(); continue; } gMtx.unlock(); std::this_thread::sleep_for(std::chrono::microseconds(10)); } }
int main() { std::thread t1(PrintCountFun,1); std::thread t2(PrintCountFun,2); std::thread t3(PrintCountFun,3);
t1.detach(); t2.detach(); t3.detach();
isRun = true; while(!isFinished) { std::this_thread::sleep_for(std::chrono::microseconds(100)); } std::cout << "finished\n"; return 0; }
|
方法1代码运行结果
反正是通过编号判断的,肯定不会错,只不过这样效率其实很低。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| 1 - 140173660395072 - c: 1 2 - 140173652002368 - c: 2 3 - 140173643609664 - c: 3 1 - 140173660395072 - c: 4 2 - 140173652002368 - c: 5 3 - 140173643609664 - c: 6 1 - 140173660395072 - c: 7 2 - 140173652002368 - c: 8 3 - 140173643609664 - c: 9 1 - 140173660395072 - c: 10 2 - 140173652002368 - c: 11 3 - 140173643609664 - c: 12 1 - 140173660395072 - c: 13 2 - 140173652002368 - c: 14 3 - 140173643609664 - c: 15 1 - 140173660395072 - c: 16 2 - 140173652002368 - c: 17 3 - 140173643609664 - c: 18 1 - 140173660395072 - c: 19 2 - 140173652002368 - c: 20 3 - 140173643609664 - c: 21 1 - 140173660395072 - c: 22 2 - 140173652002368 - c: 23 3 - 140173643609664 - c: 24 1 - 140173660395072 - c: 25 2 - 140173652002368 - c: 26 3 - 140173643609664 - c: 27 1 - 140173660395072 - c: 28 2 - 140173652002368 - c: 29 3 - 140173643609664 - c: 30 1 - 140173660395072 - c: 31 2 - 140173652002368 - c: 32 3 - 140173643609664 - c: 33 1 - 140173660395072 - c: 34 2 - 140173652002368 - c: 35 3 - 140173643609664 - c: 36 1 - 140173660395072 - c: 37 2 - 140173652002368 - c: 38 3 - 140173643609664 - c: 39 1 - 140173660395072 - c: 40 2 - 140173652002368 - c: 41 3 - 140173643609664 - c: 42 1 - 140173660395072 - c: 43 2 - 140173652002368 - c: 44 3 - 140173643609664 - c: 45 1 - 140173660395072 - c: 46 2 - 140173652002368 - c: 47 3 - 140173643609664 - c: 48 1 - 140173660395072 - c: 49 2 - 140173652002368 - c: 50 3 - 140173643609664 - c: 51 1 - 140173660395072 - c: 52 2 - 140173652002368 - c: 53 3 - 140173643609664 - c: 54 1 - 140173660395072 - c: 55 2 - 140173652002368 - c: 56 3 - 140173643609664 - c: 57 1 - 140173660395072 - c: 58 2 - 140173652002368 - c: 59 3 - 140173643609664 - c: 60 1 - 140173660395072 - c: 61 2 - 140173652002368 - c: 62 3 - 140173643609664 - c: 63 1 - 140173660395072 - c: 64 2 - 140173652002368 - c: 65 3 - 140173643609664 - c: 66 1 - 140173660395072 - c: 67 2 - 140173652002368 - c: 68 3 - 140173643609664 - c: 69 1 - 140173660395072 - c: 70 2 - 140173652002368 - c: 71 3 - 140173643609664 - c: 72 1 - 140173660395072 - c: 73 2 - 140173652002368 - c: 74 3 - 140173643609664 - c: 75 1 - 140173660395072 - c: 76 2 - 140173652002368 - c: 77 3 - 140173643609664 - c: 78 1 - 140173660395072 - c: 79 2 - 140173652002368 - c: 80 3 - 140173643609664 - c: 81 1 - 140173660395072 - c: 82 2 - 140173652002368 - c: 83 3 - 140173643609664 - c: 84 1 - 140173660395072 - c: 85 2 - 140173652002368 - c: 86 3 - 140173643609664 - c: 87 1 - 140173660395072 - c: 88 2 - 140173652002368 - c: 89 3 - 140173643609664 - c: 90 1 - 140173660395072 - c: 91 2 - 140173652002368 - c: 92 3 - 140173643609664 - c: 93 1 - 140173660395072 - c: 94 2 - 140173652002368 - c: 95 3 - 140173643609664 - c: 96 1 - 140173660395072 - c: 97 2 - 140173652002368 - c: 98 3 - 140173643609664 - c: 99 1 - 140173660395072 - c: 100 finished
|
我刚开始的时候就是想着用条件变量,比如三个条件变量分别用于通知……但这个实在是复杂且没有必要,没做过条件变量练习一时半会完全是写不出来的。后来就换了这个思路,但时间已经来不及了。
说来惭愧,我写完上面代码的基本框架后编译错误,显示atomic<bool>
初始化失败,我找了好久都没有发现是自己没有引用<atomic>
这个头文件导致的,一直在看自己的语法是不是写错了……
还是自己练习不够,不然也不会怀疑自己语法是否写错😣
思路2-条件变量
上述的这个单锁加遍历的思路其实并不是一个好的答案(但总比没写出来的好),因为它完全没有涉及到线程同步的机制,三个线程其实毫无关系,只是在通过锁竞争和判断来确定自己是否需要打印。面试官想要的答案肯定得包含条件变量。
下面这个解决方案的思路同样是通过线程编号判断(只不过拆分成了三个不同的函数),每个线程打印完毕自己的,就把另外两个线程唤醒,然后被唤醒的两个线程会通过锁竞争先后进入自己的函数打印区域,判断是否是自己需要打印的部分,如果不是就继续在条件变量里面等待。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <mutex> #include <iostream> #include <thread> #include <condition_variable>
std::mutex gMtx; std::condition_variable cv; int count = 1;
void func1() { std::unique_lock<std::mutex> lc(gMtx); while(count <= 100) { while (count % 3 == 0 && count <= 100) { std::cout << std::this_thread::get_id() << " - c: " << count << std::endl; count++; cv.notify_all(); } cv.wait(lc); } cv.notify_all(); }
void func2() { std::unique_lock<std::mutex> lc(gMtx); while (count <= 100) { while (count % 3 == 1 && count <= 100) { std::cout << std::this_thread::get_id() << " - c: " << count << std::endl; count++; cv.notify_all(); } cv.wait(lc); } }
void func3() { std::unique_lock<std::mutex> lc(gMtx); while (count <= 100) { while (count % 3 == 2 && count <= 100) { std::cout << std::this_thread::get_id() << " - c: " << count << std::endl; count++; cv.notify_all(); } cv.wait(lc); } }
int main() { std::thread s1(func1); std::thread s2(func2); std::thread s3(func3);
s1.join(); s2.join(); s3.join(); std::cout << "finished\n"; return 0; }
|
方法2代码运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| 140713900033600 - c: 1 140713891640896 - c: 2 140713908426304 - c: 3 140713900033600 - c: 4 140713891640896 - c: 5 140713908426304 - c: 6 140713900033600 - c: 7 140713891640896 - c: 8 140713908426304 - c: 9 140713900033600 - c: 10 140713891640896 - c: 11 140713908426304 - c: 12 140713900033600 - c: 13 140713891640896 - c: 14 140713908426304 - c: 15 140713900033600 - c: 16 140713891640896 - c: 17 140713908426304 - c: 18 140713900033600 - c: 19 140713891640896 - c: 20 140713908426304 - c: 21 140713900033600 - c: 22 140713891640896 - c: 23 140713908426304 - c: 24 140713900033600 - c: 25 140713891640896 - c: 26 140713908426304 - c: 27 140713900033600 - c: 28 140713891640896 - c: 29 140713908426304 - c: 30 140713900033600 - c: 31 140713891640896 - c: 32 140713908426304 - c: 33 140713900033600 - c: 34 140713891640896 - c: 35 140713908426304 - c: 36 140713900033600 - c: 37 140713891640896 - c: 38 140713908426304 - c: 39 140713900033600 - c: 40 140713891640896 - c: 41 140713908426304 - c: 42 140713900033600 - c: 43 140713891640896 - c: 44 140713908426304 - c: 45 140713900033600 - c: 46 140713891640896 - c: 47 140713908426304 - c: 48 140713900033600 - c: 49 140713891640896 - c: 50 140713908426304 - c: 51 140713900033600 - c: 52 140713891640896 - c: 53 140713908426304 - c: 54 140713900033600 - c: 55 140713891640896 - c: 56 140713908426304 - c: 57 140713900033600 - c: 58 140713891640896 - c: 59 140713908426304 - c: 60 140713900033600 - c: 61 140713891640896 - c: 62 140713908426304 - c: 63 140713900033600 - c: 64 140713891640896 - c: 65 140713908426304 - c: 66 140713900033600 - c: 67 140713891640896 - c: 68 140713908426304 - c: 69 140713900033600 - c: 70 140713891640896 - c: 71 140713908426304 - c: 72 140713900033600 - c: 73 140713891640896 - c: 74 140713908426304 - c: 75 140713900033600 - c: 76 140713891640896 - c: 77 140713908426304 - c: 78 140713900033600 - c: 79 140713891640896 - c: 80 140713908426304 - c: 81 140713900033600 - c: 82 140713891640896 - c: 83 140713908426304 - c: 84 140713900033600 - c: 85 140713891640896 - c: 86 140713908426304 - c: 87 140713900033600 - c: 88 140713891640896 - c: 89 140713908426304 - c: 90 140713900033600 - c: 91 140713891640896 - c: 92 140713908426304 - c: 93 140713900033600 - c: 94 140713891640896 - c: 95 140713908426304 - c: 96 140713900033600 - c: 97 140713891640896 - c: 98 140713908426304 - c: 99 140713900033600 - c: 100 finished
|
The end
自己平时不多练习,只能大意失荆州了……