c-如何实现信号量书中的伪代码



最近我学习了一门操作系统课程,这门课程让我了解了信号量小书中的barrier伪代码。但几个小时以来,我一直在努力实现这一障碍,我似乎无法正确理解它。为了理解它,我尝试了一个简单的程序,让线程到达屏障,当所有线程到达时,让它们通过。这是我的代码:

#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>

#define NR_MAX 5
int n=NR_MAX;
int entered = 0;
pthread_mutex_t mtx;
sem_t smph;
void* bariera(void *v){
pthread_mutex_lock(&mtx);
entered++ ;
printf("thread %d have enteredn", entered);
pthread_mutex_unlock(&mtx);
if(entered == n) { 

sem_post(&smph); printf("Out %d n", entered);}
sem_wait(&smph);

sem_post(&smph);
}
int main() {
pthread_t thr[NR_MAX];
pthread_mutex_init(&mtx, NULL);
sem_init(&smph, 0, 1);
for (int i=0; i<NR_MAX; i  ){
pthread_create(&thr[i], NULL, bariera, NULL);
}
for(int i=0; i<NR_MAX; i  ){
pthread_join(thr[i], NULL);
}
return 0;
}

实际应该如何实施?因为目前,它只打印他们到达屏障的订单,然后只打印最后一个到达的订单。

编辑:完全忘记了,这是伪代码:

n = the number of threads
count = 0  - keeps track of how many threads arrived at the barrier
mutex = Semaphore (1)  - provides exclusive acces to count
barrier = Semaphore (0) - barrier is locked (zero or negative) until all threads arrive; then it should be unlocked(1 or more)

rendezvous
2
3 mutex.wait()
4 count = count + 1
5 mutex.signal ()
6
7 if count == n: barrier.signal ()
8
9 barrier.wait()
10 barrier.signal ()
11
12 critical point

预期输出:

Out 5
Out 4 
Out 3 
Out 2
Out 1

(订单不一定相同(

实际输出:

Out 5

三个问题:

  • 信号量初始化错误
  • 访问关键部分之外的entered
  • printf放置错误
  • 缺少return
  • 循环中缺少增量
void* bariera(void *v) {
int id = (int)(uintptr_t)v;
printf("[%d] Before barrier.n", id);
pthread_mutex_lock(&mtx);
if(++entered == n) 
sem_post(&smph);  // Wake up a thread.
pthread_mutex_unlock(&mtx);
sem_wait(&smph);  // Barrier.
sem_post(&smph);  // Wake up another thread.
// Do something after the barrier.
printf("[%d] After barrier.n", id);
return NULL;
}
sem_init(&smph, 0, 0);  // Should initially be zero.
for (int i=0; i<NR_MAX; ++i) {
pthread_create(&thr[i], NULL, bariera, (void*)(intptr_t)i);
}

输出:

[0] Before barrier.
[2] Before barrier.
[3] Before barrier.
[4] Before barrier.
[1] Before barrier.
[1] After barrier.
[0] After barrier.
[3] After barrier.
[2] After barrier.
[4] After barrier.

这使得屏障信号灯不可重用。修复它,因为它发布了n+1次。为了让它回到原来的状态,我们只需要发布n次。

void* bariera(void *v) {
int id = (int)(uintptr_t)v;
printf("[%d] Before barrier.n", id);
pthread_mutex_lock(&mtx);
if(++entered == n)
for (int i=n; i--; )
sem_post(&smph);  // Wake up every thread.
pthread_mutex_unlock(&mtx);
sem_wait(&smph);  // Barrier.
// Do something after the barrier.
printf("[%d] After barrier.n", id);
return NULL;
}

使用C11原子类型,您实际上不需要单独的互斥来保护对屏障计数器的访问,如下所示。这个版本还将与屏障相关的变量和操作封装到一个结构和函数中,并且不要求最后一个到达屏障的线程也必须等待信号量。

#include <stdatomic.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
struct barrier {
int maxcount;
_Atomic int count;
sem_t sem;
};
void barrier_init(struct barrier *b, int count) {
b->maxcount = b->count = count;
sem_init(&b->sem, 0, 0);
}
void barrier_destroy(struct barrier *b) {
sem_destroy(&b->sem);
}
void barrier_wait(struct barrier *b) {
// Atomically subtract a number and return the *old* value
if (atomic_fetch_sub_explicit(&b->count, 1, memory_order_acq_rel) == 1) {
// Wake up all waiting threads as they're all at the barrier now
for (int n = 0; n < b->maxcount - 1; n += 1) {
sem_post(&b->sem);
}
} else {
sem_wait(&b->sem); // Actual barrier; wake for wakeup
}
}
void* wait_func(void *vb) {
struct barrier *b = vb;
printf("Thread 0x%x before barrier.n", (unsigned)pthread_self());
barrier_wait(b);
printf("Thread 0x%x after barrier.n", (unsigned)pthread_self());
return NULL;
}
#define NTHREADS 5
int main(void) {
pthread_t threads[NTHREADS];
struct barrier b;
barrier_init(&b, NTHREADS);
for (int n = 0; n < NTHREADS; n += 1) {
pthread_create(&threads[n], NULL, wait_func, &b);
}
for (int n = 0; n < NTHREADS; n += 1) {
pthread_join(threads[n], NULL);
}
barrier_destroy(&b);
return 0;
}

最新更新