Проблема в выполнении двух или более потоков одного типа - Pthread C - PullRequest
0 голосов
/ 23 мая 2019

Мне нужно сделать программу, использующую библиотеку pthreads C, для работы с потоками.Текст задания гласит:

Существует коридор, который имеет одну полосу движения для двух направлений, и есть два типа сотрудников, которые пересекут коридор, чтобы добраться до его противоположной стороны.Есть сотрудники типа 1, которые идут слева направо, и сотрудники типа 2, которые идут справа налево.В этом коридоре есть служитель, который очищает этот коридор, когда через него никто не проходит.При уборке коридора сотрудники обеих сторон ждут его окончания, в противном случае, если коридор занят, работник говорит, что он не может убрать и заснуть 1 секунду.

Если во время исполненияпрограммы я хотел смоделировать двух или более сотрудников одного типа, проходящих через, в том смысле, что, пока сотрудник типа X находится в коридоре, один или несколько дополнительных сотрудников этого типа прибывают и хотят воспользоваться разрешениемпередать уже приобретенный для первого, как я мог это сделать?

Вот мой код до сих пор:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

//global variables 
int c1, c2; //counters for imp1, imp2
pthread_mutex_t m1, m2;
sem_t corridor; 
double clean = 0.5;

//implementation thread attendant
void *attendant(void *arg){
    sleep(1); //rest 1 seconds
    if (c1 == 0 && c2 == 0) {
        sem_wait(&corridor);
        printf("I'm starting to clean up\n");
        sleep(clean);
        printf("I finished cleaning\n");
        sem_post(&corridor);
    } else {
       printf("I can't clean, the corridor is busy\n");
    }

    return NULL;
}


//thread employee type 1
void *emp1(void *arg) {
    printf("I'm the number %d of em1\n", c1);
    pthread_mutex_lock(&m1); //beginning critical section
    c1++;                    //it increases to signal the presence of a thread of the same type that wants to enter the corridor
    if (c1 == 1){            //the thread is the only one in the corridor. Can pass
        printf ("I am the first of my group emp1\n");
        sem_wait(&corridor);  //takes possession of the corridor
    }
    pthread_mutex_unlock(&m1); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical section

    // invents "passage" function

    pthread_mutex_lock(&m1);  //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
    c1--;
    if (c1 == 0) {
        printf("I am the last of my group emp1\n");
        sem_post(&corridor);
    } //if c1 == 0, it is the last thread imp1 and releases the corridor
    pthread_mutex_unlock(&m1); //end critical section
    return NULL;
}


//thread employee type 2 
void *emp2(void *arg){
    printf("I'm the number %d of emp2\n", c2);
    pthread_mutex_lock(&m2); //beginning critical section
    c2++;                    //it increases to signal the presence of a thread of the same type that wants to enter the corridor
    if (c2 == 1) {           // the thread is the only one in the corridor. Can pass
        printf("I am the first of my group emp2\n");
        sem_wait(&corridor);  //takes possession of the corridor
    }
    pthread_mutex_unlock(&m2); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical sectionritica

    // invents "passage" function

    pthread_mutex_lock(&m2);  //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
    c2--;
    if (c2 == 0){
        printf ("I am the last of my group emp2\n");
        sem_post(&corridor);
    }//if c1 == 0, it is the last thread imp1 and releases the corridor
    pthread_mutex_unlock(&m2); //end critical section
    return NULL;
}


int main(int argc, char const *argv[]) {
    //pthread_t emp1, emp2, attendant;
    pthread_t idt;
    int r; //var random to create thread emp1 or emp2
    int i; //index 

    //variable initialization
    c1 = c2 = 0;
    pthread_mutex_init(&m1, NULL); 
    pthread_mutex_init(&m2, NULL);
    sem_init(&corridor,0,1); 

    pthread_create(&idt, NULL, attendant, NULL); 
    while (i < 40){
        sleep(1);
        r = rand() % 2;
        if (r == 0) {
            printf("Employee creation 1\n");
            pthread_create(&idt,NULL,emp1,NULL);
        } else {
            printf("Employee creation 2\n");
            pthread_create(&idt,NULL,emp2,NULL);
        }
        i++;
        pthread_join(idt, NULL);
    }
    return 0;
}

1 Ответ

3 голосов
/ 23 мая 2019

Обобщения

Для реализации

, пока сотрудник типа X находится в коридоре, один или несколько дополнительныхсотрудники такого типа прибывают и хотят воспользоваться уже полученным разрешением для первого

, сначала вам нужно сделать так, чтобы эта ситуация даже возникла.В настоящее время у вас никогда не бывает более одного emp1 или emp2 потока (объединенного) в любой момент времени, потому что вы присоединяетесь к каждому из них перед началом другого.Я думаю, что для этой симуляции вы хотите реализовать случайную задержку между сотрудниками в дополнение к случайному типу сотрудников, запустить все потоки сотрудников с этими задержками между ними, а затем присоединить их все только после того, как они все были запущены.

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

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

Хотя семафоры могут отлично использоваться для некоторых проблем синхронизации потоковситуация, требующая, чтобы потоки сменялись или приобретали владение некоторой ограниченной вещью, обычно требует разделяемой переменной, представляющей принадлежащую вещь / ход, мьютекс, защищающий доступ к этой переменной, и условную переменную, помогающую потокам в ожидании их возможности продолжить.


Подход к реализации

В основном необходимо отслеживать две вещи:

  1. Какой тип сотрудника в настоящее время владеет коридором (тип 1, тип 2, или сопровождающий )

    enum { ATTENDANT, TYPE1, TYPE2 } corridor_owner;
    

    и

  2. Сколько сотрудниковв настоящее время находятся в коридоре.

    int corridor_occupancy;
    

Кроме того, все потоки должны полагаться на один и тот же мьютекс для защиты доступа к этим данным

pthread_mutex_t corridor_mutex = PTHREAD_MUTEX_INITIALIZER;

и им также понадобится общее резюме

pthread_cond_t corridor_cv = PTHREAD_COND_INITIALIZER;

Имея это, вот достаточно хороший способ решения проблемы:

Когда работник(нить) типа 1 или 2 хочет войти в коридор , они должны выполнить следующую процедуру:

  1. Получить мьютекс.
  2. Проверить, принадлежит ли коридор в настоящее времядругой тип сотрудника, и он уже занят:
    • , если это так, дождитесь резюме и, вернувшись из ожидания, перезапустите шаг (2);
    • , если нет, запросите коридор для еговведите тип сотрудника (возможно, с избыточностью) и увеличьте количество занятых в коридоре.
  3. Отключите мьютекс

Обратите внимание, что это позволяет нескольким сотрудникам одного типа проходить черезкоридор в то же время.

Когда оператор хочет войти в коридор , он выполняет другую процедуру:

  1. Получение мьютекса.
  2. Проверьте, является ли коридорпринадлежит другому типу сотрудника и уже занята:
    • , если это так, сначала отпустите мьютекс, затем поспите одну секунду, затем вернитесь к шагу (1);
    • , если нет,запросить коридор для его типа сотрудника, увеличить счетчик занятости коридора, а затем освободить мьютекс.

Когда сотрудник любого типа покидает коридор , он должен

  1. получить мьютекс
  2. уменьшить счетчик занятости
  3. , если счетчик занятости равен нулю, то разбудить все потоки, ожидающие на CV
  4. освободи мьютекс

Кроме того, когда поток обслуживающего персонала покидает коридор, он должен поспать некоторое время, а затем вернуться назад, чтобы попытаться снова выполнить очистку - поскольку вы в настоящее время реализовали это, он очищается только один раз. Вам также нужно либо реализовать какой-то сигнал для остановки потока обслуживающего персонала, либо сделать его потоком демона (а не пытаться присоединиться к нему).

...