Некоторые подсказки, чтобы избежать тупика в этой программе на языке C - PullRequest
1 голос
/ 28 апреля 2019

У меня есть 1 Tasker, который действует как производитель, и 3 CPU, которые действуют как потребители и общие ресурсы.Tasker читает файл и помещает его в общий ресурс, а процессоры исполняют и удаляют его.Я использовал кольцевую очередь для FIFO.Проблема, которую я обнаружил, состоит в том, что потоки ЦП не завершаются после того, как завершается работа моего Tasker из-за условных переменных, то есть они все еще ждут, пока Tasker добавит что-то для их удаления.Я хочу, чтобы общий ресурс очищался до того, как я просто уничтожил потоки процессора, но они зашли в тупик.Извините, код немного грязный и изменился из-за моих отладок.Буду признателен, если кто-нибудь из вас даст мне несколько советов о том, как это сделать.Спасибо.

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h> //used for exit
#include <string.h>
#include <unistd.h> // sleep function
#include <string.h>
#include <stdbool.h>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t not_full = PTHREAD_COND_INITIALIZER;  //check till not full
pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER; //till not empty

void *task(void *n); //function of pthread
void *cpu(void *n);  //function of pthread

typedef struct
{
    int *buffer; //;//dynamic buffer
    int head;
    int tail;
    int buffsize;
    int state;
} queue;

//globals
pthread_t tid, cid1, cid2, cid3; //id
//queue *ptr;               //our object
FILE *fwptr; //log file
int tasker;

int main()
{
    queue pt; //initialize first
    queue *ptr = &pt;
    ptr->head = 0;
    ptr->tail = 0;
    ptr->buffer = (int *)malloc(sizeof(int) * 5);
    ptr->buffsize = 5;

    fwptr = fopen("fnew.txt", "w+"); //log

    pthread_create(&tid, NULL, &task, ptr);
    sleep(1);
    pthread_create(&cid1, NULL, &cpu, ptr);
    //pthread_create(&cid1, NULL, &cpu, ptr);
    pthread_create(&cid2, NULL, &cpu, ptr);
    pthread_create(&cid3, NULL, &cpu, ptr);
    pthread_join(tid, NULL);
    //pthread_mutex_lock(&lock);
    tasker = 1; //tasker finished so now close when empty, noneed ot mutex bc 1 writer
    //pthread_mutex_unlock(&lock);
    printf("Main finish1 \n");
    //pthread_exit(&cid1);
    pthread_join(cid1, NULL);
    printf("Main finish2 \n");
    pthread_join(cid2, NULL);
    pthread_join(cid3, NULL);

    fclose(fwptr);
    return 0;
}

//TASK///////////////////
void *task(void *param)
{
    queue *ptr = (queue *)param;
    FILE *frptr = fopen("task_file", "r");
    if (frptr == NULL)
        printf("Reader File not opened");

    int burst;
    char data[15];
    // int i=0;
    int c = 1;
    while ((fscanf(frptr, "%s %d", data, &burst)) != EOF)
    {

        pthread_mutex_lock(&lock);
        if (((ptr->head + 1) % ptr->buffsize) == ptr->tail) //adding remainder here too
        {                                                   //check full condition
            printf("full and Writer waiting\n");
            pthread_cond_wait(&not_full, &lock);
        }

        ptr->buffer[ptr->head] = burst;              //write burst time in buffer
        ptr->head = (ptr->head + 1) % ptr->buffsize; // for ring queue

        printf("Tasker Writes data : %s   %d \n", data, burst);
        fprintf(fwptr, "Tasker is Writing : %s %d \n", data, burst);
        if (burst == 20)
            ptr->state = 1;

        pthread_mutex_unlock(&lock);
        pthread_cond_broadcast(&not_empty);
        //sleep(0.25);
        c++;
    }
    printf("End of file");
    tasker = 1;
    fclose(frptr);
    pthread_exit(0);
}

//CPU////////////////
void *cpu(void *param)
{
    queue *ptr = (queue *)param;
    int bt, i = 0, j = 0;
    //sleep(1);
    for (;;)
    {
        pthread_mutex_lock(&lock);
        //printf("%s", tasker ? "true" : "false");

        if (ptr->head == ptr->tail)
        {                        //check empty condition
            if (ptr->state == 1) //if tasker finished
            {
                printf(" I quit");
                break;
            }
            printf("CPU head %d tail %d \n", ptr->head, ptr->tail);
            //printf("Tasker: %s \n",tasker?"TRUE":"FALSE" );
            printf("Tasker: %d \n", tasker);
            printf("CPU waiting \n");
            pthread_cond_wait(&not_empty, &lock);
        }
        if (ptr->head == ptr->tail)
        {                        //check empty condition
            if (ptr->state == 1) //if tasker finished
            {
                printf(" I quit");
                break;
            }
        }

        bt = ptr->buffer[ptr->tail];
        printf(" Execute blast time: %d \n", bt);

        //if ((ptr->head == ptr->tail) && (tasker == 1))
        //{ //check empty condition
        //ptr->state=1;
        //}
        // printf("CPU head %d tail %d \n",ptr->head,ptr->tail );
        fprintf(fwptr, "CPU is Writing : %d \n", bt);
        ptr->tail = (ptr->tail + 1) % ptr->buffsize;
        //printf("CPU waiting \n" );
        //if (ptr->state = 1) break;
        //printf("CPU waiting1 \n" );
        pthread_mutex_unlock(&lock);
        //printf("CPU waiting2 \n" );
        pthread_cond_signal(&not_full);
        //printf("CPU waiting3 \n" );
    }
    printf("I broke \n");
    //pthread_cancel(pthread_self());
    pthread_exit(0);
}

1 Ответ

0 голосов
/ 30 апреля 2019

Есть несколько проблем.

  1. Вы должны сделать pthread_cond_signal() и pthread_cond_broadcast() с заблокированным мьютексом.В настоящее время они находятся вне мьютекса.

  2. Вы должны разблокировать мьютекс перед тем, как прервать цикл в процессоре ().

      if (ptr->state == 1) //if tasker finished
        {
            printf(" I quit");
            pthread_mutex_unlock(&lock); //Unlock
            break;
        }
    

Я думаю,# 2 - настоящая проблема здесь.Один из потоков ЦП завершает работу с заблокированным мьютексом, а другой поток ожидает мьютекса навсегда.

Обновление Вы разделяете ресурсы между двумя потоками ЦП.В настоящее время для каждого производства данных производитель вещает.Это может вызвать некоторые проблемы, так как ваш код потребления данных не находится под if (ptr->head != ptr->tail). На мой взгляд, вы должны сделать еще два изменения, чтобы он работал правильно.

  1. В функции производителя (task()),Вы не должны использовать pthread_cond_broadcast(), но использовать pthread_cond_signal().Однако в конце, то есть, когда ptr->state равен 1, вы можете транслировать, как вам нужно, чтобы разблокировать все потоки.
  2. В функции потребителя (cpu()) поместите часть потребления в if (ptr->head != ptr->tail) какниже.

A

   if (ptr->head == ptr->tail)
    {                        //check empty condition
        if (ptr->state == 1) //if tasker finished
        {
            //unlock mutex and break
        }
        //Wait for signal
    }

    if (ptr->head == ptr->tail)
    {                        //check empty condition
        if (ptr->state == 1) //if tasker finished
        {
            //unlock mutex and break
        }
    }
    else
    {
        bt = ptr->buffer[ptr->tail];
        //Rest of the consumption code
        ...
    }
...