1. 按序打印
题目来源于力扣 1114。测序程序:
void print1() { cout << "first"; }
void print2() { cout << "second"; }
void print3() { cout << "third"; }
int main() {
Foo fo;
thread th1(&Foo::first, &fo, print1);
thread th2(&Foo::second, &fo, print2);
thread th3(&Foo::third, &fo, print3);
th1.join();
th2.join();
th3.join();
}
方法 1 互斥锁:设置两把锁并锁住,用于阻止线程 2 和线程 3 运行。线程 1 运行完打开线程 2 的锁,线程 2 运行完打开线程 3 的锁。
class Foo {
mutex mtx_1, mtx_2;
unique_lock<mutex> lock_1, lock_2;
public:
Foo() : lock_1(mtx_1, try_to_lock), lock_2(mtx_2, try_to_lock) {} // second和third线程被锁住。
void first(function<void()> printFirst) {
printFirst();
lock_1.unlock(); // second线程解锁。
}
void second(function<void()> printSecond) {
lock_guard<mutex> guard(mtx_1); // 获取second线程的锁mtx_1。
printSecond();
lock_2.unlock();
}
void third(function<void()> printThird) {
lock_guard<mutex> guard(mtx_2);
printThird();
}
};
2. 交替打印
题目来源于力扣 1115。测序程序:
#include<iostream>
#include<thread>
using namespace std;
void print1() { cout << "Foo" << endl; }
void print2() { cout << "Bar" << endl; }
int main() {
FooBar fo(10);
thread th1(&FooBar::foo, &fo, print1);
thread th2(&FooBar::bar, &fo, print2);
th1.join();
th2.join();
}
方法 1 循环等待:
class FooBar {
public:
FooBar(int x) :n(x), index(1) {}
void foo(function<void()> printFoo) {
for (int i = 0; i < n; i++) {
while (index != 1)
this_thread::yield();
printFoo();
index = 2;
}
}
void bar(function<void()> printBar) {
for (int i = 0; i < n; i++) {
while (index != 2)
this_thread::yield();
printBar();
index = 1;
}
}
private:
int n, index;
};
简单来说就是在线程中使用 while。循环等待,第7行和第15行可以是空循环体。这两行的作用是主动让出CPU时间片,避免不间断地判断循环条件。
疑问:这种方法能保证 index 一致性吗。测试程序创建线程时 fo 为什么要加 &。
方法 2 条件变量:
class FooBar {
public:
FooBar(int x) :n(x), index(1) {}
void foo(function<void()> printFoo) {
for (int i = 0; i < n; i++) {
unique_lock<mutex> lock(mt); //为了防止竞争,条件变量总是和一个互斥锁结合使用。
cv.wait(lock, [this]() { return index == 1; }); //阻塞该线程直到满足条件。
printFoo();
index = 2;
cv.notify_one(); //发信号并随机唤醒一个等待的线程。
}
}
void bar(function<void()> printBar) {
for (int i = 0; i < n; i++) {
unique_lock<mutex> lock(mt);
cv.wait(lock, [this]() { return index == 2; });
printBar();
index = 1;
cv.notify_one();
}
}
private:
int n, index;
condition_variable cv;
mutex mt;
};