leetcode多线程合集

    科技2022-07-15  115

    1114. 按序打印

    与1116题类似,使用condition_variable.

    class Foo { public: Foo() { } mutex mtx; atomic<int> g{1}; condition_variable cv; void first(function<void()> printFirst) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return g == 1; }); // printFirst() outputs "first". Do not change or remove this line. printFirst(); g = 2; cv.notify_all(); } void second(function<void()> printSecond) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return g == 2; }); // printSecond() outputs "second". Do not change or remove this line. printSecond(); g = 3; cv.notify_all(); } void third(function<void()> printThird) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return g == 3; }); // printThird() outputs "third". Do not change or remove this line. printThird(); g = 1; cv.notify_all(); } };

    1115. 交替打印FooBar

    实现方法比较多.

    方法一:condition_variable

    class FooBar { private: int n; mutex mtx; condition_variable cv; public: FooBar(int n) { this->n = n; } bool flag{false}; void foo(function<void()> printFoo) { unique_lock<mutex> lck(mtx); for (int i = 0; i < n; i++) { cv.wait(lck, [this]{return !(this->flag);}); // printFoo() outputs "foo". Do not change or remove this line. printFoo(); this->flag = true; cv.notify_all(); } } void bar(function<void()> printBar) { unique_lock<mutex> lck(mtx); for (int i = 0; i < n; i++) { cv.wait(lck, [this]{return this->flag;}); // printBar() outputs "bar". Do not change or remove this line. printBar(); this->flag = false; cv.notify_all(); } } };

    方法二:信号量

    #include <semaphore.h> class FooBar { private: int n; sem_t sem_foo; sem_t sem_bar; public: FooBar(int n) { this->n = n; sem_init(&sem_foo, 0, 1); sem_init(&sem_bar, 0, 0); } void foo(function<void()> printFoo) { for (int i = 0; i < n; i++) { sem_wait(&sem_foo); // printFoo() outputs "foo". Do not change or remove this line. printFoo(); sem_post(&sem_bar); } } void bar(function<void()> printBar) { for (int i = 0; i < n; i++) { sem_wait(&sem_bar); // printBar() outputs "bar". Do not change or remove this line. printBar(); sem_post(&sem_foo); } } };

    方法三:原子变量

    class FooBar { private: int n; atomic<bool> flag{false}; public: FooBar(int n) { this->n = n; } void foo(function<void()> printFoo) { for (int i = 0; i < n; i++) { while(flag.load(std::memory_order_acquire)) { std::this_thread::yield(); } // printFoo() outputs "foo". Do not change or remove this line. printFoo(); flag.store(true, std::memory_order_release); } } void bar(function<void()> printBar) { for (int i = 0; i < n; i++) { while(!flag.load(std::memory_order_acquire)) { std::this_thread::yield(); } // printBar() outputs "bar". Do not change or remove this line. printBar(); flag.store(false, std::memory_order_release); } } };

    1116. 打印零与奇偶数

    方法一:使用信号量sem_t

    逻辑比较简单,如果理解信号量sem_t的使用的话。

    #include <semaphore.h> class ZeroEvenOdd { private: int n; sem_t zero_s; sem_t odd_s; sem_t even_s; public: ZeroEvenOdd(int n) { this->n = n; sem_init(&zero_s, 0, 1); sem_init(&odd_s, 0, 0); sem_init(&even_s, 0, 0); } // printNumber(x) outputs "x", where x is an integer. void zero(function<void(int)> printNumber) { for(int i = 1; i <= n; i++) { sem_wait(&zero_s); printNumber(0); if(i & 1) { sem_post(&odd_s); } else { sem_post(&even_s); } } } void even(function<void(int)> printNumber) { for(int i = 2; i <= n; i+=2) { sem_wait(&even_s); printNumber(i); sem_post(&zero_s); } } void odd(function<void(int)> printNumber) { for(int i = 1; i <= n; i+=2) { sem_wait(&odd_s); printNumber(i); sem_post(&zero_s); } } };

    方法二:使用mutex

    与信号量逻辑差不多,只是改用了mutex。

    class ZeroEvenOdd { private: int n; mutex lck[3]; public: ZeroEvenOdd(int n) { this->n = n; lck[0].unlock(); lck[1].lock(); lck[2].lock(); } // printNumber(x) outputs "x", where x is an integer. void zero(function<void(int)> printNumber) { for(int i = 1; i <= n; i++) { lck[0].lock(); printNumber(0); if(i & 1) { lck[2].unlock(); } else { lck[1].unlock(); } } } void even(function<void(int)> printNumber) { for(int i = 2; i <= n; i += 2) { lck[1].lock(); printNumber(i); lck[0].unlock(); } } void odd(function<void(int)> printNumber) { for(int i = 1; i <= n; i += 2) { lck[2].lock(); printNumber(i); lck[0].unlock(); } } };

    1195. 交替打印字符串

    与上面的题差不多,可以使用多种方法。

    方法一:条件变量

    使用一个atomic<int> 表示当前计数,看其能否被3和5整除。

    class FizzBuzz { private: int n; mutex mtx; condition_variable cv; atomic<int> g{1}; public: FizzBuzz(int n) { this->n = n; } // printFizz() outputs "fizz". void fizz(function<void()> printFizz) { while(g <= n) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return (g > n) || (g % 3 == 0 && g % 5 != 0); }); if(g > n) break; //注意这里和上面wait函数中的条件 printFizz(); g++; cv.notify_all(); } } // printBuzz() outputs "buzz". void buzz(function<void()> printBuzz) { while(g <= n) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return (g > n) || (g % 5 == 0 && g % 3 != 0); }); if(g > n) break; printBuzz(); g++; cv.notify_all(); } } // printFizzBuzz() outputs "fizzbuzz". void fizzbuzz(function<void()> printFizzBuzz) { while(g <= n) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return (g > n) || (g % 3 == 0 && g % 5 == 0); }); if(g > n) break; printFizzBuzz(); g++; cv.notify_all(); } } // printNumber(x) outputs "x", where x is an integer. void number(function<void(int)> printNumber) { while(g <= n) { unique_lock<mutex> lck(mtx); cv.wait(lck, [this]{ return (g > n) || (g % 3 != 0 && g % 5 != 0); }); if(g > n) break; printNumber(g); g++; cv.notify_all(); } } };

    需要注意wait函数中的一个条件(g > n),以及:if(g > n) break;,不加这两句有的线程不会退出。

    方法二:原子变量

    class FizzBuzz { private: int n; atomic<int> g{1}; public: FizzBuzz(int n) { this->n = n; } // printFizz() outputs "fizz". void fizz(function<void()> printFizz) { while(g.load() <= n) { if(g % 3 == 0 && g % 5 != 0) { printFizz(); g++; } this_thread::yield(); } } // printBuzz() outputs "buzz". void buzz(function<void()> printBuzz) { while(g.load() <= n) { if(g % 3 != 0 && g % 5 == 0) { printBuzz(); g++; } this_thread::yield(); } } // printFizzBuzz() outputs "fizzbuzz". void fizzbuzz(function<void()> printFizzBuzz) { while(g.load() <= n) { if(g % 3 == 0 && g % 5 == 0) { printFizzBuzz(); g++; } this_thread::yield(); } } // printNumber(x) outputs "x", where x is an integer. void number(function<void(int)> printNumber) { while(g.load() <= n) { if(g % 3 != 0 && g % 5 != 0) { printNumber(g); g++; } this_thread::yield(); } } };

    方法三:信号量

    #include <semaphore.h> #include <functional> #include <thread> using namespace std; class FizzBuzz { private: int n; int cur; sem_t sem_fizz; sem_t sem_buzz; sem_t sem_fizz_buzz; sem_t sem_num; public: FizzBuzz(int n) { this->n = n; cur = 1; sem_init(&sem_fizz, 0, 0); sem_init(&sem_buzz, 0, 0); sem_init(&sem_fizz_buzz, 0, 0); sem_init(&sem_num, 0, 1); } // printFizz() outputs "fizz". void fizz(function<void()> printFizz) { while(cur <= n){ // 这里的while是为了在cur超过n之前,一直可以打印fizz,不然打印完一次之后就执行完了,sem_post唤醒没有用 sem_wait(&sem_fizz); if(cur > n) break; printFizz(); cur++; sem_post(&sem_num); } } // printBuzz() outputs "buzz". void buzz(function<void()> printBuzz) { while(cur <= n){ sem_wait(&sem_buzz); if(cur > n) break; printBuzz(); cur++; sem_post(&sem_num); } } // printFizzBuzz() outputs "fizzbuzz". void fizzbuzz(function<void()> printFizzBuzz) { while(cur <= n){ sem_wait(&sem_fizz_buzz); if(cur > n) break; printFizzBuzz(); cur++; sem_post(&sem_num); } } // printNumber(x) outputs "x", where x is an integer. void number(function<void(int)> printNumber) { while(cur <= n) { sem_wait(&sem_num); if(cur>n) break; if(cur % 3 == 0 && cur % 5 == 0){ sem_post(&sem_fizz_buzz); }else if(cur % 3 == 0){ sem_post(&sem_fizz); }else if(cur % 5 == 0){ sem_post(&sem_buzz); }else{ printNumber(cur); cur ++; sem_post(&sem_num); } } // 以下三个post通过更新sem_fizz等信号量,调动其他线程运行,进而结束所有线程,调用这个函数时,其它三个线程才会结束 sem_post(&sem_fizz); sem_post(&sem_buzz); sem_post(&sem_fizz_buzz); } };
    Processed: 0.017, SQL: 8