多线程-1115. 交替打印 FooBar

52 阅读1分钟

1115. 交替打印 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 实例:

  • 线程 A 将会调用 foo() 方法,而
  • 线程 B 将会调用 bar() 方法

请设计修改程序,以确保 "foobar" 被输出 n 次。

 

示例 1:

输入: n = 1
输出: "foobar"
解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。

示例 2:

输入: n = 2
输出: "foobarfoobar"
解释: "foobar" 将被输出两次。

 

提示:

  • 1 <= n <= 1000

个人思路

思路与算法

解法:

定义两个信号量, 控制两个线程进程同步 初始化t1=1, t2=0, foo线程执行, bar线程阻塞 foo执行完成, 阻塞foo, 并且同事bar执行 bar执行完成,阻塞bar,通知foo执行.

代码

#include <semaphore.h>
class FooBar {
private:
    int n;
    sem_t t1;
    sem_t t2;
public:
    FooBar(int n) {
        this->n = n;
        sem_init(&t1,0,1);
        sem_init(&t2,0,0);
    }

    void foo(function<void()> printFoo) {
        
        for (int i = 0; i < n; i++) {
            sem_wait(&t1);
        	// printFoo() outputs "foo". Do not change or remove this line.
        	printFoo();
            sem_post(&t2);
        }
    }

    void bar(function<void()> printBar) {
        
        for (int i = 0; i < n; i++) {
            sem_wait(&t2);
        	// printBar() outputs "bar". Do not change or remove this line.
        	printBar();
            sem_post(&t1);
        }
    }
};

image.png

解法:利用双信号量

代码

#include <semaphore.h>
class FooBar {
 private:
  int n;
  sem_t f_, b_;
 public:
  FooBar(int n) {
    this->n = n;
    sem_init(&f_, 0, 1);
    sem_init(&b_, 0, 0);
  }

  void foo(function<void()> printFoo) {
    for (int i = 0; i < n; i++) {
      sem_wait(&f_);
      printFoo();
      sem_post(&b_);
    }
  }

  void bar(function<void()> printBar) {
    for (int i = 0; i < n; i++) {
      sem_wait(&b_);
      printBar();
      sem_post(&f_);
    }
  }
};

image.png 每天记录一下做题思路。

解题思路 两个互斥锁的方法就不要学了,写不好就容易死锁。这里提供3个靠谱的方法。

代码

原子操作

    class FooBar {
    private:
    int n;
    atomic<bool> foo_done = false;
    public:
    FooBar(int n) : n(n) {}

        void foo(function<void()> printFoo) {
            for (int i = 0; i < n; i++) {
                while (foo_done) {
                    this_thread::yield();
                }
                printFoo();
                foo_done = true;
            }
        }

        void bar(function<void()> printBar) {
            for (int i = 0; i < n; i++) {
                while (!foo_done) {
                    this_thread::yield();
                }
                printBar();
                foo_done = false;
            }
        }

    };

互斥锁+条件变量

    
    class FooBar {
    private:
    int n;
    mutex mtx;
    condition_variable cv;
    bool foo_done = false;
    public:
    FooBar(int n) : n(n) {}

        void foo(function<void()> printFoo) {
            for (int i = 0; i < n; i++) {
                unique_lock<mutex> lock(mtx);
                cv.wait(lock, [&]() { return !foo_done; });
                printFoo();
                foo_done = true;
                cv.notify_one();
            }
        }

        void bar(function<void()> printBar) {
            for (int i = 0; i < n; i++) {
                unique_lock<mutex> lock(mtx);
                cv.wait(lock, [&]() { return foo_done; });
                printBar();
                foo_done = false;
                cv.notify_one();
            }
        }

    };

信号量

    \#include \<semaphore.h> // 需要手动包含信号量头文件

    class FooBar {
    private:
    int n;
    sem_t foo_done, bar_done;
    public:
    FooBar(int n) : n(n) {
    sem_init(\&foo_done, 0 , 0);
    sem_init(\&bar_done, 0 , 1);
    }

        void foo(function<void()> printFoo) {
            for (int i = 0; i < n; i++) {
                sem_wait(&bar_done);
                printFoo();
                sem_post(&foo_done);
            }
        }

        void bar(function<void()> printBar) {
            for (int i = 0; i < n; i++) {
                sem_wait(&foo_done);
                printBar();
                sem_post(&bar_done);
            }
        }

    };