交替打印FooBar
题目描述:
我们提供一个类:
class FooBar {
public void foo() {
for (int i = 0; i < n; i++) {
print("foo");
}
}
public void bar() {
for (int i = 0; i < n; i++) {
print("bar");
}
}
}
两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。
请设计修改程序,以确保 “foobar” 被输出 n 次。
示例 1:
输入: n = 1
输出: "foobar"
解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。
示例 2:
输入: n = 2
输出: "foobarfoobar"
解释: "foobar" 将被输出两次。
解题思路:
两个锁,分别控制foo()和bar()的输出
代码实现:
class FooBar {
private:
int n;
mutex m1,m2;
public:
FooBar(int n) {
this->n = n;
m2.lock();
}
void foo(function<void()> printFoo) {
for (int i = 0; i < n; i++) {
/*
* printFoo()首次将会被执行
* 其后的每次执行都需要依靠printBar()函数执行完之后的解锁才能再次执行
*/
m1.lock();
// printFoo() outputs "foo". Do not change or remove this line.
printFoo();
m2.unlock();
}
}
void bar(function<void()> printBar) {
for (int i = 0; i < n; i++) {
m2.lock();
// printBar() outputs "bar". Do not change or remove this line.
// printBar()的每次执行都需要printFoo()执行完之后的解锁才能执行
printBar();
m1.unlock();
}
}
};
打印零与奇偶数
题目描述:
每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506… ,其中序列的长度必须为 2n。
示例 1:
输入:n = 2
输出:"0102"
说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 "0102"。
示例 2:
输入:n = 5
输出:"0102030405"
解题思路:
- 三个锁,一个变量
- 三个锁分别控制奇数、偶数和0的输出
- 一个变量控制0后的输出为奇数还是偶数
代码实现:
class ZeroEvenOdd {
private:
int n;
mutex m1,m2,m3;
int order;//决定0后面打印奇数还是偶数
public:
ZeroEvenOdd(int n) {
this->n = n;
order = 0;
m1.lock();//控制打印奇数的锁
m2.lock();//控制打印偶数的锁
}
// printNumber(x) outputs "x", where x is an integer.
void zero(function<void(int)> printNumber) {
for(int i = 0; i < n; ++i)//打印n次0
{
m3.lock();
printNumber(0);
if(order == 0)//打印奇数
{
order = 1;
m1.unlock();
}
else //打印偶数
{
order = 0;
m2.unlock();
}
}
}
void even(function<void(int)> printNumber) { // 偶数
for(int i = 2; i <= n; i += 2){
m2.lock();
printNumber(i);
m3.unlock();
}
}
void odd(function<void(int)> printNumber) { //奇数
for(int i = 1; i <= n; i += 2){
m1.lock();
printNumber(i);
m3.unlock();
}
}
};
按序打印
题目描述:
我们提供了一个类:
public class Foo {
public void one() { print("one"); }
public void two() { print("two"); }
public void three() { print("three"); }
}
三个不同的线程将会共用一个 Foo 实例。
线程 A 将会调用 one() 方法
线程 B 将会调用 two() 方法
线程 C 将会调用 three() 方法
请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。
示例 1:
输入: [1,2,3]
输出: "onetwothree"
解释:
有三个线程会被异步启动。
输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。
正确的输出是 "onetwothree"。
示例 2:
输入: [1,3,2]
输出: "onetwothree"
解释:
输入 [1,3,2] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 three() 方法,线程 C 将会调用 two() 方法。
正确的输出是 "onetwothree"。
解题思路:
- 两个锁
- 第一把锁保证two() 方法在 one() 方法之后被执行
- 第二把锁保证three() 方法在 two() 方法之后被执行。
代码实现:
class Foo {
private:
mutex m1,m2;
public:
Foo() {
m1.lock();
m2.lock();
}
void first(function<void()> printFirst) {
// printFirst() outputs "first". Do not change or remove this line.
//printFirst()总是会被首先执行
printFirst();
m1.unlock();
}
void second(function<void()> printSecond) {
// printSecond() outputs "second". Do not change or remove this line.
//printSecond()总是会在printFirst()执行完释放锁后执行
m1.lock();
printSecond();
m2.unlock();
}
void third(function<void()> printThird) {
m2.lock();
// printThird() outputs "third". Do not change or remove this line.
//printThird()总是会在printSecond()执行完释放锁后执行
printThird();
}
};
H2O 生成
题目描述:
现在有两种线程,氢 oxygen 和氧 hydrogen,你的目标是组织这两种线程来产生水分子。
存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来。
氢和氧线程会被分别给予 releaseHydrogen 和 releaseOxygen 方法来允许它们突破屏障。
这些线程应该三三成组突破屏障并能立即组合产生一个水分子。
你必须保证产生一个水分子所需线程的结合必须发生在下一个水分子产生之前。
换句话说:
如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
书写满足这些限制条件的氢、氧线程同步代码。
示例 1:
输入: "HOH"
输出: "HHO"
解释: "HOH" 和 "OHH" 依然都是有效解。
示例 2:
输入: "OOHHHH"
输出: "HHOHHO"
解释: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" 和 "OHHOHH" 依然都是有效解。
解题思路:
- 两个锁和一个变量
- 两个锁分别控制H和O的输出
- 一个变量控制H的输出个数
代码实现:
class H2O {
private:
int hCount;//保证H的输出个数为2
mutex m1,m2;//分别控制H和O的输出
public:
H2O() {
hCount = 0;
m2.lock();
}
void hydrogen(function<void()> releaseHydrogen) {
m1.lock();
// releaseHydrogen() outputs "H". Do not change or remove this line.
/*
* releaseHydrogen()首次将会被执行
* 其后的每次执行都需要releaseOxygen()执行完释放锁后才能执行
*/
releaseHydrogen();
hCount++;
/*
* 当hCount != 2时,需要解m1的锁,保证releaseHydrogen()再次被执行
* 当hCount == 2时,需要解m2的锁,保证releaseOxygen()能够被执行
*/
if(hCount != 2)
m1.unlock();
else
m2.unlock();
}
void oxygen(function<void()> releaseOxygen) {
m2.lock();
// releaseOxygen() outputs "O". Do not change or remove this line.
//releaseOxygen()总是会在releaseHydrogen()执行完释放m2锁后被执行
releaseOxygen();
hCount = 0;
m1.unlock();
}
};