#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define NUM_READERS 5
#define NUM_WRITERS 5
// 定義信號量和全局變量
sem_t sdata, srcount;
int readcount = 0;
// 建議在每個線程中使用局部隨機數生成,不重復調用srand()(可在主線程調用一次)
?
void* reader(void* p) {
? ? int id = *(int*)p + 1;
? ? // 為每個線程設置一個線程局部種子,使用線程ID與時間混合生成
? ? unsigned int seed = time(NULL) ^ id;
? ? while (1) {
? ? ? ? int sleepTime = rand_r(&seed) % 5 + 1; // 隨機[1,5]秒
? ? ? ? // 進入讀者協議
? ? ? ? sem_wait(&srcount);
? ? ? ? readcount++;
? ? ? ? if (readcount == 1) { // 第一個讀者鎖定共享資源
? ? ? ? ? ? sem_wait(&sdata);
? ? ? ? }
? ? ? ? sem_post(&srcount);
? ? ? ? // 模擬讀操作
? ? ? ? printf("讀者 %d 開始讀取...\n", id);
? ? ? ? sleep(sleepTime);
? ? ? ? printf("讀者 %d 讀取完成,耗時 %d 秒\n", id, sleepTime);
? ? ? ? // 離開讀者協議
? ? ? ? sem_wait(&srcount);
? ? ? ? readcount--;
? ? ? ? if (readcount == 0) { // 最后一個讀者釋放共享資源
? ? ? ? ? ? sem_post(&sdata);
? ? ? ? }
? ? ? ? sem_post(&srcount);
? ? ? ? sleep(1); // 讀者操作后稍作延時,再嘗試下一次讀取
? ? }
? ? return NULL;
}
void* writer(void* p) {
? ? int id = *(int*)p + 1;
? ? unsigned int seed = time(NULL) ^ id;
? ? while (1) {
? ? ? ? int sleepTime = rand_r(&seed) % 5 + 1; // 隨機寫入時間
? ? ? ? // 寫者請求進入共享資源
? ? ? ? sem_wait(&sdata);
? ? ? ? printf("寫者 %d 開始寫入...\n", id);
? ? ? ? sleep(sleepTime);
? ? ? ? printf("寫者 %d 寫入完成,耗時 %d 秒\n", id, sleepTime);
? ? ? ? sem_post(&sdata);
? ? ? ? sleep(1); // 寫者操作后延時
? ? }
? ? return NULL;
}
int main(void) {
? ? int i;
? ? // 初始化信號量
? ? sem_init(&sdata, 0, 1);
? ? sem_init(&srcount, 0, 1);
? ? pthread_t readers[NUM_READERS], writers[NUM_WRITERS];
? ? int thread_ids[NUM_READERS > NUM_WRITERS ? NUM_READERS : NUM_WRITERS];
? ??
? ? // 初始化隨機種子只需一次(如果需要全局 seed 可在此設定)
? ? srand(time(NULL));
? ? // 創建讀者線程
? ? for (i = 0; i < NUM_READERS; i++) {
? ? ? ? thread_ids[i] = i;
? ? ? ? pthread_create(&readers[i], NULL, reader, &thread_ids[i]);
? ? }
? ? // 創建寫者線程
? ? for (i = 0; i < NUM_WRITERS; i++) {
? ? ? ? thread_ids[i] = i;
? ? ? ? pthread_create(&writers[i], NULL, writer, &thread_ids[i]);
? ? }
? ? // 等待所有線程結束(實際上本示例為無限循環,可使用其他退出條件)
? ? for (i = 0; i < NUM_READERS; i++) {
? ? ? ? pthread_join(readers[i], NULL);
? ? }
? ? for (i = 0; i < NUM_WRITERS; i++) {
? ? ? ? pthread_join(writers[i], NULL);
? ? }
? ??
? ? sem_destroy(&sdata);
? ? sem_destroy(&srcount);
? ? return 0;
}
?