Tôi có một chương trình đơn giản bằng C mô phỏng vấn đề đọc-ghi. Yêu cầu người dùng nhập số lượng tác giả và độc giả. Sau đó tạo một chuỗi ghi và chuỗi đọc số ngẫu nhiên. Việc ghi các mục được mô phỏng bằng biến toàn cục itemsCount - nó đại diện cho ID của mục mới được chèn (itemsCount + 1). Tôi nghĩ rằng chương trình hoạt động tốt vào thời điểm này.
Nhưng bây giờ tôi phải hiển thị xung đột ghi do đồng bộ hóa ghi sai. Tôi nghĩ chỉ cần xóa câu lệnh là đủ sem_wait(&w);
Hoặc khởi tạo sai semaphore - ví dụ: sem_init(&w,0,5);
Nhưng nó không làm gì cả và tôi không thể thấy bất kỳ xung đột văn bản nào. Tôi nghĩ, ở đầu ra tôi sẽ thấy một cái gì đó như:
Nhà văn 1 ghi các mục --> Số mục: 1 Tên thành phần: Nhà văn 1
Writer 2 viết mục --> Số mục: 1 Tên phần tử: Writer 2
(Xung đột: Hai mục có một số). Nhưng không có điều này xảy ra.
Tôi đã sai ở đâu?
Mã có tính đồng bộ tốt:
#include
#include
#include
#include
#defineMAX_READERS 10
#defineMAX_WRITERS 10
sem_t w; // ngữ nghĩa cho quyền truy cập ghi
sem_t m; // mutex
int rc=0; // số lượng người đọc
int writerCount; // người dùng muốn có bao nhiêu nhà văn
int readerCount; // người dùng muốn có bao nhiêu độc giả
pthread_t writerThread[MAX_WRITERS*5], readerThread[MAX_READERS*5] // chủ đề dành cho người viết và người đọc
int writeCount[MAX_WRITERS], readCount[MAX_READERS] // mỗi người viết và mỗi người đọc đã đọc bao nhiêu lần
int itemsCount=0; // có bao nhiêu mục được lưu trữ trong "DB"
void *nhà văn(void *i)
{
int a = *((int *) i);
sem_wait(&w); // P(w)
printf("Người viết %d ghi mục --> số mục: %d | tên mục: Người viết %d\n", a+1, ++itemsCount, a+1);
writeCount[a]++;
sem_post(&w); // V(w)
return 0;
}
void *reader(void *i)
{
int a = *((int *) i);
sem_wait(&m); // P(m)
RC++;
nếu (rc == 1) {
sem_wait(&w); // P(w)
}
sem_post(&m); // V (m)
printf("Trình đọc %d đọc từ DB.\n", a+1);
readCount[a]++;
sem_wait(&m); // P(m)
rc--;
nếu (rc == 0) {
sem_post(&w); // V(w)
}
sem_post(&m); // V(m)
return 0;
}
int RandomCount() // trả về số nguyên ngẫu nhiên trong khoảng từ 1 đến 5
{
trả về 1 + 5.0 * rand() / RAND_MAX;
}
int main()
{
srand(thời gian(NULL));
sem_init(&w,0,1); // khởi tạo semaphore
sem_init(&m,0,1);
int i;
printf("Nhập số lượng người viết (tối đa %d):", MAX_WRITERS);
scanf("%d",&writersCount);
if (writersCount > MAX_WRITERS) {
fprintf(stderr, "Số lượng wirters tối đa là: %d\n", MAX_WRITERS);
return 1;
}
printf("Nhập số lượng người đọc (tối đa %d):", MAX_READERS);
scanf("%d",&readersCount);
if (writersCount > MAX_READERS) {
fprintf(stderr, "Số lượng độc giả tối đa là %d\n", MAX_READERS);
return 1;
}
printf("----------------------------------------------------------\n ");
int readerIndexes[readersCount]; // chỉ mục của trình đọc (sẽ được chuyển tới luồng)
int writerIndexes[readersCount]; // chỉ mục của nhà văn (sẽ được chuyển tới luồng)
int TotalReaders = 0;
int TotalWriters = 0;
for (i=0; i
{
int j;
số int;
readerIndexes[i] = i;
đếm = RandomCount();
for (j=0; j
{
pthread_create(&readersThread[totalReaders++], NULL, reader, &readerIndexes[i]);
}
}
for (i = 0; i
{
int j;
số int;
writerIndexes[i] = i;
đếm = RandomCount();
for (j=0;j
{
pthread_create(&writersThread[totalWriters++], NULL, nhà văn, &writerIndexes[i]);
}
}
for (i=0;i
{
pthread_join(writerThread[i], NULL);
}
cho (i=0;i<>
{
pthread_join(readersThread[i], NULL);
}
printf("----------------------------------------------------------\n ");
cho (i=0;i<>
{
printf("Người đọc %d đọc %d lần\n", i+1, readCount[i]);
}
cho (i=0;i<>
{
printf("Người viết %d đã viết %d lần\n", i+1, writeCount[i]);
}
sem_destroy(&w);
sem_destroy(&m);
return 0;
}
Đầu ra:
Nhập số lượng người viết (tối đa 10):5
Nhập số lượng độc giả (tối đa 10):5
----------------------------------------
Reader 1 đọc từ DB.
Reader 1 đọc từ DB.
Reader 2 đọc từ DB.
Reader 2 đọc từ DB.
Reader 2 đọc từ DB.
Reader 2 đọc từ DB.
Reader 3 đọc từ DB.
Reader 3 đọc từ DB.
Reader 4 đọc từ DB.
Reader 4 đọc từ DB.
Reader 4 đọc từ DB.
Nhà văn 1 viết mục --> số lượng mục: 1 | tên mục: Nhà văn 1
Nhà văn 1 viết mục --> số lượng mục: 2 | tên mục: Nhà văn 1
Nhà văn 1 viết mục --> số lượng mục: 3 | tên mục: Nhà văn 1
Nhà văn 2 viết mục --> số lượng mục: 4 | Tên mục: Nhà văn 2
Nhà văn 2 viết mục --> số lượng mục: 5 | Tên mục: Nhà văn 2
Nhà văn 2 ghi mục --> số mục: 6 | Tên mục: Nhà văn 2
Nhà văn 3 ghi mục --> số mục: 7 | Tên mục: Nhà văn 3
Nhà văn 3 viết mục --> số lượng mục: 8 | Tên mục: Nhà văn 3
Nhà văn 3 ghi mục --> số mục: 9 | Tên mục: Nhà văn 3
Nhà văn 3 ghi mục --> số mục: 10 | Tên mục: Nhà văn 3
Nhà văn 4 ghi mục --> số mục: 11 | Tên mục: Nhà văn 4
Nhà văn 5 ghi mục --> số mục: 12 | Tên mục: Nhà văn 5
Nhà văn 5 ghi mục --> số mục: 13 | Tên mục: Nhà văn 5
Nhà văn 5 ghi mục --> số mục: 14 | Tên mục: Nhà văn 5
Reader 4 đọc từ DB.
Reader 4 đọc từ DB.
Reader 5 đọc từ DB.
Reader 5 đọc từ DB.
Reader 5 đọc từ DB.
Reader 5 đọc từ DB.
----------------------------------------
Đầu đọc 1 đọc 2 lần
Đầu đọc 2 đọc 4 lần
Đầu đọc 3 đọc 2 lần
Đầu đọc 4 đọc 5 lần
Đầu đọc 5 đọc 4 lần
Tác giả 1 đã viết 3 lần
Tác giả 2 đã viết 3 lần
Tác giả 3 đã viết 4 lần
Tác giả 4 viết 1 lần
Tác giả 5 đã viết 3 lần
Cảm ơn bạn rất nhiều
Có rất ít khả năng bạn sẽ thấy bộ lập lịch của hệ điều hành làm gián đoạn luồng của bạn một vài hướng dẫn sau khi thức dậy (sem_wait) và một hướng dẫn trước hàng rào bộ nhớ (sem_post).
Như bạn có thể thấy từ nhật ký, trình đọc chỉ được thực thi tuần tự mà không cần chuyển ngữ cảnh không cần thiết (làm tốt lắm, trình lập lịch trình!).
Tôi nghĩ nếu bạn viết lại mã của mình như thế này:
int v = writeCount[a], cnt;
for (int cnt = 0; cnt < 1000; cnt++) {;} // một số spinlock lớn
writeCount[a] = v + 1;
- Bạn sẽ có thể chứng minh xung đột viết.
Tôi là một lập trình viên xuất sắc, rất giỏi!