C/C++ 线程同步实践
例题说明。
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