Учитывая эти методы:
void* thread1Func(void* p) {
while(1) {
printf("A ");
}
}
void* thread2Func(void* p) {
while(1) {
printf("B ");
}
}
void* thread3Func(void* p) {
while(1) {
printf("C ");
}
}
Предполагая, что поток 1 запускает поток 1Func, то же самое для потоков 2 и 3,
Нам необходимо добавлять только семафоры/методы семафоров/методы потоков (создание, выполнение) так, чтобы напечатанный шаблон был A A B C A A B C A A B C A A B C ...
У меня есть код, распечатывающий правильный шаблон без ошибок:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t semaphoreA, semaphoreB, semaphoreC;
void* thread1Func(void* p) {
while (1) {
sem_wait(&semaphoreA); // Wait for semaphoreA
printf("A ");
sem_post(&semaphoreA); // Signal semaphoreA for the second 'A'
sem_wait(&semaphoreA); // Wait for semaphoreA again
printf("A ");
sem_post(&semaphoreB); // Signal semaphoreB for 'B'
}
}
void* thread2Func(void* p) {
while (1) {
sem_wait(&semaphoreB); // Wait for semaphoreB
printf("B ");
sem_post(&semaphoreC); // Signal semaphoreC for 'C'
}
}
void* thread3Func(void* p) {
while (1) {
sem_wait(&semaphoreC); // Wait for semaphoreC
printf("C ");
sem_post(&semaphoreA); // Signal semaphoreA for the next 'A'
}
}
int main() {
pthread_t thread1, thread2, thread3;
// Initialize semaphores
sem_init(&semaphoreA, 0, 1); // semaphoreA starts unlocked
sem_init(&semaphoreB, 0, 0); // semaphoreB starts locked
sem_init(&semaphoreC, 0, 0); // semaphoreC starts locked
// Create threads
pthread_create(&thread1, NULL, thread1Func, NULL);
pthread_create(&thread2, NULL, thread2Func, NULL);
pthread_create(&thread3, NULL, thread3Func, NULL);
// Wait for threads to finish (which they won't in this case due to while(1))
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
// Destroy semaphores
sem_destroy(&semaphoreA);
sem_destroy(&semaphoreB);
sem_destroy(&semaphoreC);
return 0;
}
Однако это решение предполагает добавление еще одного оператора печати, что запрещено.
Я пробовал разные подходы к увеличению/уменьшению семафоров, но все они либо терпят неудачу, либо печатают шаблон.
A B C A B C A B C A B C ...
Я поигрался с методами ожидания/отправки, а также с начальным значением семафора. У меня есть этот код, который дал мне правильный шаблон, однако я не уверен, почему это работает:
(добавил только те части, где я изменил значения)
sem_t semaphoreA, semaphoreB, semaphoreC;
void* thread1Func(void* p) {
while (1) {
sem_wait(&semaphoreA); // Wait for semaphoreA
printf("A "); // Print 'A'
sem_post(&semaphoreB); // Signal semaphoreB for 'B'
sem_post(&semaphoreC); // Signal semaphoreC for 'C'
}
}
void* thread2Func(void* p) {
while (1) {
sem_wait(&semaphoreB); // Wait for semaphoreB
sem_wait(&semaphoreB);
printf("B "); // Signal semaphoreA for the next 'A'
}
}
void* thread3Func(void* p) {
while (1) {
sem_wait(&semaphoreC); // Wait for semaphoreC
sem_wait(&semaphoreC);
printf("C "); // Print 'C' and newline
sem_post(&semaphoreA); // Signal semaphoreA for the next 'A'
sem_post(&semaphoreA);
}
}
int main() {
// Initialize semaphores
sem_init(&semaphoreA, 0, 2); // semaphoreA starts unlocked
sem_init(&semaphoreB, 0, -1); // semaphoreB starts locked
sem_init(&semaphoreC, 0, -1); // semaphoreC starts locked
// ...
}
В качестве подсказки, потому что вы почти поняли: После 2 A
должен быть 1 B
. После 1 B
должен быть 1 C
. После 1 C
должно быть 2 A
и т. д. Ваша реализация: после 2 A
должны быть B
и C
(что тоже может быть CB
)...
Я думаю, что-то вроде этого сработает:
void* thread1Func(void* p) {
while (1) {
sem_wait(&semaphoreA); // Wait for semaphoreA
printf("A "); // Print 'A'
sem_post(&semaphoreB); // Signal semaphoreB for 'B'
}
}
void* thread2Func(void* p) {
while (1) {
sem_wait(&semaphoreB); // Wait for semaphoreB
sem_wait(&semaphoreB);
printf("B "); // Signal semaphoreA for the next 'A'
sem_post(&semaphoreC); // Signal semaphoreC for 'C'
}
}
void* thread3Func(void* p) {
while (1) {
sem_wait(&semaphoreC); // Wait for semaphoreC
printf("C "); // Print 'C' and newline
sem_post(&semaphoreA); // Signal semaphoreA for the next 'A'
sem_post(&semaphoreA); // Signal semaphoreA for the next 'A'
}
}
та же проблема, это может быть A A B C
или A A C B
. И ты сделал semaphoreA
неправильно, так что может быть A A A A A A A A A ....
.
Я понимаю, что ты имеешь в виду, думаю, теперь стало лучше
Вы слишком задумываетесь о проблеме. Во-первых, подумайте о том, что должно произойти на каждом логическом этапе.
Ваш поток A заботится только о своем повороте и разблокировке B, поэтому начните с него.
void* thread1Func(void* p) {
while (1) {
sem_wait(&semaphoreA); // Wait for semaphoreA
printf("A ");
sem_post(&semaphoreB); // Signal semaphoreB for 'B'
}
}
Теперь, чтобы B заработал, ему нужно подождать дважды, так как нам всегда нужны два A.
void* thread2Func(void* p) {
while (1) {
sem_wait(&semaphoreB); // Wait for semaphoreB
sem_wait(&semaphoreB); // Wait for semaphoreB
printf("B ");
sem_post(&semaphoreC); // Signal semaphoreC for 'C'
}
}
Наконец, C должен дважды подать сигнал A, поскольку нам нужны два отпечатка.
void* thread3Func(void* p) {
while (1) {
sem_wait(&semaphoreC); // Wait for semaphoreC
printf("C ");
sem_post(&semaphoreA); // Signal semaphoreA for the next 'A'
sem_post(&semaphoreA); // Signal semaphoreA for the next 'A'
}
}
Единственное, что вам нужно изменить, это начальное значение semaphoreA
на 2 (sem_init(&semaphoreA, 0, 2)
), чтобы цикл выполнялся дважды.
Просто ответ, который мне нужен, какой, по вашему мнению, является правильным подходом к работе с семафорами? Я понял, как хорошо работают блокировки мьютексов (они проще по сравнению с семафорами, вот как я это вижу)
Какой у Вас вопрос? Почему это работает? Это не работает. Я понимаю, как это может сработать, если повезет, но
B
иC
тоже можно поменять местами.