例题说明。

1. Print in Order

C 实现,使用 pthread 库,互斥锁 + 条件变量。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <time.h>

typedef struct {
    short count;
    pthread_cond_t cond;
    pthread_mutex_t mutex;
} Foo;

Foo* fooCreate();

void first(Foo* obj);

void second(Foo* obj);

void third(Foo* obj);

void fooFree(Foo* obj);

void printFirst();

void printSecond();

void printThird();

int main(void) {
    time_t t;
    srand((unsigned) time(&t));
    short a = -1, b = -1, c = -1;
    while (a == b || b == c || a == c) {
        a = rand() % 3;
        b = rand() % 3;
        c = rand() % 3;
    }
    Foo *f = fooCreate();
    pthread_t th[3];
    pthread_create(&th[a], NULL, (void *(*)(void *))first, f);
    pthread_create(&th[b], NULL, (void *(*)(void *))third, f);
    pthread_create(&th[c], NULL, (void *(*)(void *))second, f);
    pthread_join(th[a], NULL);
    pthread_join(th[b], NULL);
    pthread_join(th[c], NULL);
    fooFree(f);
    return 0;
}

Foo* fooCreate() {
    Foo* obj = (Foo*) malloc(sizeof(Foo));
    pthread_cond_init(&obj->cond, NULL);
    pthread_mutex_init(&obj->mutex, NULL);
    obj->count = 1;
    return obj;
}

void first(Foo* obj) {
    pthread_mutex_lock(&obj->mutex);
    while (obj->count != 1)
        pthread_cond_wait(&obj->cond, &obj->mutex);
    printFirst();
    obj->count = 2;
    pthread_mutex_unlock(&obj->mutex);
    pthread_cond_broadcast(&obj->cond);
}

void second(Foo* obj) {
    pthread_mutex_lock(&obj->mutex);
    while (obj->count != 2)
        pthread_cond_wait(&obj->cond, &obj->mutex);
    printSecond();
    obj->count = 3;
    pthread_mutex_unlock(&obj->mutex);
    pthread_cond_broadcast(&obj->cond);
}

void third(Foo* obj) {
    pthread_mutex_lock(&obj->mutex);
    while (obj->count != 3)
        pthread_cond_wait(&obj->cond, &obj->mutex);
    printThird();
    obj->count = 1;
    pthread_mutex_unlock(&obj->mutex);
    pthread_cond_broadcast(&obj->cond);
}

void fooFree(Foo* obj) {
    pthread_cond_destroy(&obj->cond);
    pthread_mutex_destroy(&obj->mutex);
    free(obj);
}

void printFirst() {
    printf("first");
}

void printSecond() {
    printf("second");
}

void printThird() {
    printf("third");
}

输出:

firstsecondthird

2. Print FooBar Alternately

C 实现,同样使用 pthread 库,互斥锁 + 条件变量。

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> 

typedef struct {
    bool flag;
    pthread_cond_t cond;
    pthread_mutex_t mutex;
    int n;
} FooBar;

FooBar* fooBarCreate(int n);

void foo(FooBar* obj);

void bar(FooBar* obj);

void fooBarFree(FooBar* obj);

void printFoo();

void printBar();

int main(void) {
    int n = 0;
    scanf("%d", &n);
    FooBar *fb = fooBarCreate(n);
    pthread_t a, b;
    pthread_create(&a, NULL, (void *(*)(void *))foo, fb);
    pthread_create(&b, NULL, (void *(*)(void *))bar, fb);
    pthread_join(a, NULL);
    pthread_join(b, NULL);
    fooBarFree(fb);
    return 0;
}

FooBar* fooBarCreate(int n) {
    FooBar* obj = (FooBar*) malloc(sizeof(FooBar));
    pthread_cond_init(&obj->cond, NULL);
    pthread_mutex_init(&obj->mutex, NULL);
    obj->flag = true;
    obj->n = n;
    return obj;
}

void foo(FooBar* obj) {
    for (int i = 0; i < obj->n; i++) {
        pthread_mutex_lock(&obj->mutex);
        while (obj->flag != true) {
            pthread_cond_wait(&obj->cond, &obj->mutex);
        }
        printFoo();
        obj->flag = false;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

void bar(FooBar* obj) {
    for (int i = 0; i < obj->n; i++) {
        pthread_mutex_lock(&obj->mutex);
        while (obj->flag != false) {
            pthread_cond_wait(&obj->cond, &obj->mutex);
        }
        printBar();
        obj->flag = true;
        pthread_mutex_unlock(&obj->mutex);
        pthread_cond_broadcast(&obj->cond);
    }
}

void fooBarFree(FooBar* obj) {
    pthread_cond_destroy(&obj->cond);
    pthread_mutex_destroy(&obj->mutex);
    free(obj);
}


void printFoo() {
    printf("foo");
}

void printBar() {
    printf("bar");
}

输入: 5

输出:

foobarfoobarfoobarfoobarfoobar

3. Print Zero Even Odd

C++ 实现,使用 thread 和 condition_variable。

#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;

void printNumber(int n);

class ZeroEvenOdd {
private:
    int n;
    int counter;
    bool is_zero;
    bool is_even;
    bool is_exit;
    mutex mtx;
    condition_variable cv;
public:
    explicit ZeroEvenOdd(int n) : n(n), counter(false), is_zero(true), is_even(false), is_exit(false) {}

    void zero(function<void(int)>);

    void even(function<void(int)>);

    void odd(function<void(int)>);
};

int main() {
    int n = 0;
    cin >> n;
    ZeroEvenOdd zeo(n);
    thread t1(&ZeroEvenOdd::zero, ref(zeo), ref(printNumber));
    thread t2(&ZeroEvenOdd::even, ref(zeo), ref(printNumber));
    thread t3(&ZeroEvenOdd::odd, ref(zeo), ref(printNumber));
    t1.join();
    t2.join();
    t3.join();
    return 0;
}

void printNumber(int n) {
    cout << n;
}

void ZeroEvenOdd::zero(function<void(int)>) {
    while (true) {
        unique_lock<mutex> lk(mtx);
        cv.wait(lk, [this] { return this->is_zero || this->is_exit; });
        if (this->is_exit)
            return;
        printNumber(0);
        is_zero = !is_zero;
        lk.unlock();
        cv.notify_all();
    }
}

void ZeroEvenOdd::even(function<void(int)>) {
    while (true) {
        unique_lock<mutex> lk(mtx);
        cv.wait(lk, [this] { return (this->is_even && !this->is_zero) || this->is_exit; });
        if (this->is_exit)
            return;
        printNumber(++counter);
        this->is_exit = counter >= n;
        is_zero = !is_zero;
        is_even = !is_even;
        lk.unlock();
        cv.notify_all();
    }
}

void ZeroEvenOdd::odd(function<void(int)>) {
    while (true) {
        unique_lock<mutex> lk(mtx);
        cv.wait(lk, [this] { return (!this->is_even && !this->is_zero) || this->is_exit; });
        if (this->is_exit)
            return;
        printNumber(++counter);
        if (counter >= n)
            this->is_exit = true;
        is_zero = !is_zero;
        is_even = !is_even;
        lk.unlock();
        cv.notify_all();
    }
}

输入: 10

输出:

010203040506070809010