Переменные мьютекса буфера и условия в C

Я только начал писать многопоточность на C и не совсем понимаю, как это реализовать. Я пишу код, который считывает входной файл и помещает его в массив структуры буфера. Когда в буфере больше нет свободного места,request_t заблокирован в ожидании свободного места. Управляется потокомLift_R . Остальные нитки подъемника 1-3 работают.lift() и он записывает то, что находится в буфере, в выходной файл в зависимости от количестваint sec .sec а такжеsize и заданные значения через командную строку. Это освободит место для запроса на продолжение чтения ввода.

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

(ПРИМЕЧАНИЕ: лифт работает в режиме FIFO, а потоки используют взаимное исключение)

Это то, что я написал до сих пор, я еще не реализовал никаких условий ожидания или FIFO, в настоящее время я сосредоточен на записи в файл и отладке, и скоро я буду ждать и сигнализировать.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> 
#include "list.h"
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; //declare thread conditions
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //declare mutex
int sec; //time required by each lift to serve a request
int size; //buffer size
buffer_t A[];
write_t write;
void *lift(void *vargp)

{
    pthread_mutex_lock(&lock);
    FILE* out;
    out = fopen("sim_output.txt", "w");
    //gather information to print
    if (write.p == NULL) //only for when system begins
    {
        write.p = A[1].from;
    }
    write.rf = A[1].from;
    write.rt = A[1].to;
    write.m = (write.p - A[1].from) + (A[1].to - A[1].from);
    if (write.total_r == NULL) //for when the system first begins
    {
        write.total_r = 0;
    }
    else
    {
        write.total_r++;
    }
    if (write.total_m == NULL)
    {
        write.total_m = write.m;
    }
    else
    {
        write.total_m = write.total_m + write.m;
    }
    write.c = A[1].to;
    //Now write the information
    fprintf(out, "Previous position: Floor %d\n", write.p);
    fprintf(out, "Request: Floor %d to Floor %d\n", write.rf, write.rt);
    fprintf(out, "Detail operations:\n");
    fprintf(out, "    Go from Floor %d to Floor %d\n", write.p, write.rf);
    fprintf(out, "    Go from Floor %d to Floor %d\n", write.rf, write.rt);
    fprintf(out, "    #movement for this request: %d\n", write.m);
    fprintf(out, "    #request: %d\n", write.total_r);
    fprintf(out, "    Total #movement: %d\n", write.total_m);
    fprintf(out, "Current Position: Floor %d\n", write.c);
    write.p = write.c; //for next statement
    pthread_mutex_unlock(&lock);
    return NULL;
}


void *request_t(void *vargp)
{
    pthread_mutex_lock(&lock); //Now only request can operate
    FILE* f;
    FILE* f2;
    f = fopen("sim_input.txt", "r");
    if (f == NULL)
    {
        printf("input file empty\n");
        exit(EXIT_FAILURE);
    }
    f2 = fopen("sim_output.txt", "w");

    int i = 0;
    for (i; i < size; i++)
    {
        //read the input line by line and into the buffer
        fscanf(f, "%d %d", &A[i].from, &A[i].to);\
        //Print buffer information to sim_output
        fprintf(f2, "----------------------------\n");
        fprintf(f2, "New Lift Request from Floor %d to Floor %d \n", A[i].from, A[i].to);
        fprintf(f2, "Request No %d \n", i);
        fprintf(f2, "----------------------------\n");
    }
    printf("Buffer is full");
    fclose(f);
    fclose(f2);
    pthread_mutex_unlock(&lock);
    return NULL;
}


void main(int argc, char *argv[]) // to avoid segmentation fault
{
    size = atoi(argv[0]);
    if (!(size >= 1))
    {
        printf("buffer size too small\n");
        exit(0);
    }
    else
    {
        A[size].from = NULL;
        A[size].to = NULL;
    }
    sec = atoi(argv[1]);
    pthread_t Lift_R, lift_1, lift_2, lift_3;

    pthread_create(&Lift_R, NULL, request_t, NULL);

    pthread_join(Lift_R, NULL);

    pthread_create(&lift_1, NULL, lift, NULL);

    pthread_join(lift_1, NULL);

    pthread_create(&lift_2, NULL, lift, NULL);

    pthread_join(lift_2, NULL);

    pthread_create(&lift_3, NULL, lift, NULL);

    pthread_join(lift_3, NULL);

}

И вот файлы структуры:

#include <stdbool.h>

typedef struct Buffer
{
    int from;
    int to;
}buffer_t; //buffer arrary to store from and to values from sim_input

typedef struct Output
{
    int l; //lift number
    int p; //previous floor
    int rf; //request from
    int rt; //request to
    int total_m; //total movement
    int c; // current position
    int m; //movement
    int total_r; //total requests made
}write_t;
# multithreading pthreads buffer
Источник
Codelisting
за 2 против
Лучший ответ

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

Итак, этот паттерн:

  pthread_create(&x, ?, func, arg);
  pthread_join(x, ...);

Можно заменить на:

  func(arg);

так что вы действительно вообще не многопоточны; это точно так, как если бы:

void main(int argc, char *argv[]) // to avoid segmentation fault
{
    size = atoi(argv[0]);
    if (!(size >= 1))
    {
        printf("buffer size too small\n");
        exit(0);
    }
    else
    {
        A[size].from = NULL;
        A[size].to = NULL;
    }
    sec = atoi(argv[1]);

    request_t(0);
    lift(0);
    lift(0);
    lift(0);
}

и, зная это, я надеюсь, вы видите бесполезность в:

pthread_mutex_lock(&lock);
....
pthread_mutex_unlock(&lock);

Итак, начните с небольшого переосмысления того, что вы делаете. Похоже, у вас есть лифт, которому нужно принимать входящие запросы, возможно, сортировать их, а затем обрабатывать. Скорее всего, «навсегда».

Вероятно, это означает отсортированную очередь; однако он не отсортирован по обычным критериям. Лифт перемещается по зданию в обоих направлениях, но это позволяет минимизировать изменение направления. Это включает обход очереди как в порядке (>, <), так и в текущем направлении. Скорее всего, вы захотите, чтобы запрос просто оценил график подъема и определил, куда вставить новый запрос. График подъема будет однонаправленным списком того, куда подъемник пойдет дальше. И, возможно, правило, согласно которому список сверяется со своим списком только тогда, когда он останавливается на определенном этаже.

Таким образом, запрос может заблокировать график, изменить его, чтобы отразить новый запрос, а затем разблокировать.

Лифт может просто:

  while (!Lift_is_decommissioned) {
        pthread_mutex_lock(&glock);
        Destination = RemoveHead(&graph);
        pthread_mutex_unlock(&glock);
        GoTo(Destination);
  }

И Запрос может быть:

  pthread_mutex_lock(&glock);

  NewDestination = NewEvent.floorpressed;
  NewDirection   = NewEvent.floorpressed > NewEvent.curfloor ? Up : Down;
  i = FindInsertion(&graph, NewDestination, NewDirection);
  InsertAt(&graph, i, NewDestination);

  pthread_mutex_unlock(&glock);

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

Но при таком разделении вы можете заставить лифт просто следовать приведенному выше рецепту, а обработчики кнопок вызывают другой псевдокод, указанный выше.

Однако FindInsertion () может быть немного непростым ....

  • 0
    Извините, но pthread create, join, wait, signal, lock, unlock являются обязательными. Я не могу заменить их ничем другим. Нет func ().
  • 0
    Дело в том, что они выполняются последовательно до завершения, как если бы они вообще не были потоками.
  • 0
    Что, если я использую цикл while, чтобы повторять задачи до тех пор, пока sim_input не будет полностью прочитан.
Смежные вопросы
Codelisting
Популярные категории
На заметку программисту