最近,我學習了作業系統課程,該課程將我帶到了信號量小書中的屏障偽代碼。但是現在有幾個小時我正在努力實作這個障礙,我似乎無法正確理解它。為了理解它,我嘗試了一個簡單的程式,讓執行緒進入屏障,當所有執行緒到達時,讓它們通過。這是我的代碼:
#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 entered\n", 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
uj5u.com熱心網友回復:
三個問題:
- 未正確初始化的信號量。
entered在臨界區之外訪問。- 錯位了
printf。 - 失蹤
return。 - for 回圈中缺少增量。
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;
}
uj5u.com熱心網友回復:
對于 C11 原子型別,您實際上不需要單獨的互斥鎖來保護對屏障計數器的訪問,如下所示。這個版本也將barrier相關的變數和操作封裝成一個struct和functions,不需要最后一個碰到barrier的執行緒也必須等待信號量。
#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;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/369523.html
下一篇:C如何列印陣列指標的索引
