题意
启动多个进程,每个进程执行20000个循环。对于每一个循环周期,确保多个进程都执行到同一个点,然后继续下一次循环。
解决思路
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待“条件变量的条件成立”而挂起;另一个线程使“条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
可参考的函数使用:1
2
3条件变量的使用:
pthread_cond_wait(&cond, &mutex); // go to sleep on cond, releasing lock mutex
pthread_cond_broadcast(&cond); // wake up every thread sleeping on cond
pthread_cond_wait
会先解除之前的pthread_mutex_lock
锁定的mutex,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);
,再读取资源。
在barrier()函数中加入互斥锁和条件变量的控制:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15static void
barrier()
{
pthread_mutex_lock(&bstate.barrier_mutex);
bstate.nthread++;
if(bstate.nthread != nthread){
pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
pthread_mutex_unlock(&bstate.barrier_mutex);
}else{
pthread_cond_broadcast(&bstate.barrier_cond);
bstate.round++;
bstate.nthread = 0;
pthread_mutex_unlock(&bstate.barrier_mutex);
}
}
bstate.nthread变量的累加用于决定:由最后一个进入barrier()的线程来进行broadcast。注意到pthread_cond_wait
函数本身先释放锁、休眠、被唤醒、加锁的流程;执行broadcast之后,该线程会累加周期数bstate.round并清空bstate.nthread,然后释放锁,只有当该线程释放锁,其他线程才真正能在pthread_cond_wait
中加锁。
编译并运行:1
2
3
4
5
6$ gcc -g -O2 -pthread barrier.c
$ ./a.out 2
```
{% asset_img 1.JPG 编译并运行 %}
# 源代码
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
// #define SOL
static int nthread = 1;
static int round = 0;
struct barrier {
pthread_mutex_t barrier_mutex;
pthread_cond_t barrier_cond;
int nthread; // Number of threads that have reached this round of the barrier
int round; // Barrier round
} bstate;
static void
barrier_init(void)
{
assert(pthread_mutex_init(&bstate.barrier_mutex, NULL) == 0);
assert(pthread_cond_init(&bstate.barrier_cond, NULL) == 0);
bstate.nthread = 0;
}
static void
barrier()
{
pthread_mutex_lock(&bstate.barrier_mutex);
bstate.nthread++;
if(bstate.nthread != nthread){
pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
pthread_mutex_unlock(&bstate.barrier_mutex);
}else{
pthread_cond_broadcast(&bstate.barrier_cond);
bstate.round++;
bstate.nthread = 0;
pthread_mutex_unlock(&bstate.barrier_mutex);
}
}
static void
thread(void xa)
{
long n = (long) xa;
long delay;
int i;
for (i = 0; i < 20000; i++) {
int t = bstate.round;
assert (i == t);
barrier();
usleep(random() % 100);
}
}
int
main(int argc, char argv[])
{
pthread_t tha;
void *value;
long i;
double t1, t0;
if (argc < 2) {
fprintf(stderr, “%s: %s nthread\n”, argv[0], argv[0]);
exit(-1);
}
nthread = atoi(argv[1]);
tha = malloc(sizeof(pthread_t) * nthread);
srandom(0);
barrier_init();
for(i = 0; i < nthread; i++) {
assert(pthread_create(&tha[i], NULL, thread, (void *) i) == 0);
}
for(i = 0; i < nthread; i++) {
assert(pthread_join(tha[i], &value) == 0);
}
printf(“OK; passed\n”);
}`