leetcode多线程合集

2023-05-16

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);
    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

leetcode多线程合集 的相关文章

随机推荐