一些避免在此pthreaded C程序中死锁的提示

时间:2019-04-28 04:11:34

标签: c multithreading pthreads mutex semaphore

我有一个像生产者一样工作的Tasker和三个像消费者和共享资源一样工作的CPU。 Tasker读取文件并将其放入共享资源,然后CPU执行并删除该文件。我将环形队列用于FIFO。我发现的问题是由于条件变量,我的Tasker完成后CPU线程没有终止,即它们仍在等待Tasker添加一些东西以将其删除。我希望在清空CPU线程之前先清空共享资源,但它们陷入死锁状态。抱歉,由于我的调试,代码有些混乱并且已更改。如果您能给我一些建议,我将不胜感激。谢谢。

#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 :(得分:0)

问题很少。

  1. 您应该执行pthread_cond_signal()pthread_cond_broadcast() 互斥锁已锁定。目前它们不在互斥锁内。

  2. 在cpu()中退出循环之前,您应该解锁互斥锁。

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

我认为#2是这里的真正问题。一个CPU线程退出并已锁定互斥锁,另一个线程则永远等待该互斥锁。

更新 您正在两个CPU线程之间共享资源。当前,对于每个数据生产,生产者都在广播。这可能会引起一些问题,因为您的数据使用代码不在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
        ...
    }