Использование семафоров для печати определенного шаблона

Учитывая эти методы:

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

    // ...
}

Какой у Вас вопрос? Почему это работает? Это не работает. Я понимаю, как это может сработать, если повезет, но B и C тоже можно поменять местами.

mch 12.07.2024 15:41

В качестве подсказки, потому что вы почти поняли: После 2 A должен быть 1 B. После 1 B должен быть 1 C. После 1 C должно быть 2 A и т. д. Ваша реализация: после 2 A должны быть B и C (что тоже может быть CB)...

mch 12.07.2024 15:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, что-то вроде этого сработает:

 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 .....

mch 12.07.2024 15:52

Я понимаю, что ты имеешь в виду, думаю, теперь стало лучше

Alban 12.07.2024 15:57
Ответ принят как подходящий

Вы слишком задумываетесь о проблеме. Во-первых, подумайте о том, что должно произойти на каждом логическом этапе.

  1. Распечатать 2 как
  2. Распечатать 1 Б
  3. Распечатать 1 С

Ваш поток 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)), чтобы цикл выполнялся дважды.

Просто ответ, который мне нужен, какой, по вашему мнению, является правильным подходом к работе с семафорами? Я понял, как хорошо работают блокировки мьютексов (они проще по сравнению с семафорами, вот как я это вижу)

Anjera 13.07.2024 00:27

Другие вопросы по теме