О потоках и семафорах (POSIX семафоры)

Вопрос или проблема

Я хочу, чтобы каждый раз, когда создается студент, отображалось, кто был создан и в каком department они учатся. Я застрял и не знаю, какие параметры передать в printInfo(), есть у вас идеи? Я также предоставляю пример выполнения

Вывод:

Введите количество студентов:
5

Студент 1 (Математика) создан.

Остановка A: [1, Математика]
Автобус:
Университет:
Остановка B:

Студент 2 (Химия) создан.

Остановка A: [1, Математика] [2, Химия]
Автобус:
Университет:
Остановка B:

....

Студент 4 (Математика) создан.

Остановка A: [1, Математика] [2, Химия] [3, Физика] [5, Физика] [4, Математика]
Автобус:
Университет:
Остановка B:

и самая большая часть моего кода:

...
sem_t semaphore;
pthread_barrier_t barrier;
pthread_mutex_t mutex;

int count=0;

enum place{ 
    stopA=0,
        Bus=1,
        University=2,
        stopB=3
};

enum science{
    Math=0,
    Physics=1,
    Chemistry=2,
    CSD=3
};

struct student{
    pthread_t thread;
    int am;
    int time;
    enum place position;
    enum science department;
};
...

void initialize_students(struct student * Student, pthread_t thread, int i){
    Student->thread=thread;
    Student->am=random_number(1000,6000);
    Student->time=random_number(5,15);
    Student->position=stopA;
    Student->department=random_number(0,3);
    return;
}

void printInfo(struct student * s,int num){

    printf("\nОстановка A: ");
    for(int i=0;i<num;i++){
        if(s->position==stopA){
            printf("[%d , %s ] ",i,getScience(s[i].department));
        }
    }
    printf("\nАвтобус: ");
    for(int i=0;i<num;i++){
        if(s->position==Bus){
            printf("[%d , %s ] ",i,getScience((s+i)->department));
        }
    }
    printf("\nУниверситет: ");
    for(int i=0;i<num;i++){
        if(s->position==University){
            printf("[%d , %s ] ",i,getScience((s+i)->department));
        }
    }
    printf("\nОстановка B: ");
    for(int i=0;i<num;i++){
        if(s->position==stopB){
            printf("[%d , %s ] ",i,getScience((s+i)->department));
        }
    }
    printf("\n");
}

void * startEvent(void * args){

    struct student * s = (struct student*)args;

    pthread_mutex_lock(&mutex);

    printf("\nСтудент %d [%s] создан\n",++count,getScience(s->department));

    sleep(1);

    printInfo();

    pthread_mutex_unlock(&mutex);   
}
int main(){
    int NUM_THREADS;
    int i;

    printf("Пожалуйста, введите количество студентов:\n");
    scanf("%d", &NUM_THREADS);
        if (NUM_THREADS < 12 || NUM_THREADS > 200) {
            perror("Неверное количество студентов. Оно должно быть между 12 и 200.\n");
            return EXIT_FAILURE;
        }

    pthread_t * thread=malloc(NUM_THREADS * sizeof(pthread_t));

    srand(time(NULL));

    struct student * Students=malloc(NUM_THREADS * sizeof(struct student));

    for(i=0;i<NUM_THREADS;i++){
        initialize_students((Students+i),thread[i],i);
    }

    sem_init(&semaphore,0,NUM_THREADS);
    pthread_mutex_init(&mutex,NULL);

    for(i=0;i<NUM_THREADS;i++){

        if( pthread_create(&Students[i].thread,NULL,&startEvent,&Students[i]) != 0 ){
            perror("Ошибка при попытке создать поток\n");
        }

    }

    for(i=0;i<NUM_THREADS;i++){
        if( pthread_join(Students[i].thread,NULL) != 0 ){
            perror("Ошибка при соединении потока\n");
        }
    }
    return  0;
}

place: Представляет места, где можно найти студента (остановки A, B, автобус, университет).

science: Представляет предмет изучения студента (Математика, Физика, Химия, CSD).

thread: идентификатор потока.
am: случайное число, представляющее AM (Регистрационный номер).
time: длительность пребывания в университете.
position: текущее местоположение студента.
department: его факультет.

random_number генерирует случайное целое число в заданном диапазоне (от min до max)

Ответ или решение

Понимание потоков и семафоров (POSIX семафоры) является важной частью разработки многопоточных приложений, особенно когда необходимо координировать взаимодействие между потоками. Ваша задача состоит в том, чтобы правильно передать параметры в функцию printInfo(), чтобы она могла отобразить информацию о созданных студентах.

Параметры для передачи в printInfo()

Ваша функция printInfo() требует два параметра:

  1. Указатель на массив студентов (struct student *s)
  2. Общее количество студентов (int num)

Таким образом, код вызова printInfo() в функции startEvent() должен быть модифицирован следующим образом:

printInfo(Students, NUM_THREADS);

Это обеспечит корректное отображение информации о всех студентах. Параметр Students указывает на массив структур студентов, а NUM_THREADS позволяет функции printInfo() определить количество созданных студентов.

Обзор кода

Ваш код создает потоки для каждого студента, используя POSIX потоки и семафоры для обеспечения правильной синхронизации. Рассмотрим основные части вашего кода подробнее:

  1. Структура студента (struct student) содержит информацию о каждом студенте, включая идентификатор потока, случайный регистрационный номер, время, позицию и отделение.

  2. Функция initialize_students() инициализирует нового студента, присваивая ему уникальные значения для каждого параметра.

  3. Синхронизация с использованием pthread_mutex_t позволяет избежать конфликтов при выводе информации о студентах. Каждое создание студента и вывод информации фиксируется с помощью блокировки и разблокировки мьютекса.

  4. Вывод информации: Функция printInfo() выделяет место для каждого студента в различных категориях (остановки, автобус, университет), используя условие if для определения текущей позиции.

Рекомендации по улучшению кода

  • Инкапсуляция логики вывода: Возможно, будет гуманно разделить логику, связанную с выводом конкурентных состояний (printInfo()), и выделить её в отдельные функции. Это повысит читаемость кода и упростит изменения в будущем.

  • Управление памятью: Обязательно не забывайте освобождать выделенную память для Students и thread, чтобы избежать утечек памяти. В конце функции main() добавьте:

free(Students);
free(thread);
  • Обработка ошибок: При работе с потоками важно обрабатывать возможные ошибки, связанные с созданием или объединением потоков. Хотя у вас уже есть это в коде, вы можете добавить больше информации в сообщения об ошибках, чтобы упростить отладку.

Заключение

Использование потоков и семафоров в C может быть сложной задачей, особенно при необходимости управлять состоянием нескольких потоков. В вашем случае, правильный вызов функции printInfo() и корректная работа с потоками позволяют добиться требуемого поведения вашего приложения. Следуя данным рекомендациям, вы сможете улучшить ваш код и сделать его более устойчивым и понятным. Если у вас возникли дополнительные вопросы, не стесняйтесь спрашивать.

Оцените материал
Добавить комментарий

Капча загружается...