如何避免工作线程卡在sem_wait中?

时间:2017-11-21 21:32:52

标签: c multithreading mutex semaphore producer-consumer

我是信号量的新手,想知道如何避免我的工作线程(在多个工人单一生产者问题中)卡在sem_wait(&full)中的情况。在此之后我也有一个互斥锁,但我怀疑,这就是卡住的地方。我知道我的所有任务都已完成,但线程没有退出。所有任务完成后,程序中的生产者线程停止发送数据。

供参考......生产者线程......

 while (i<number_of_tasks)
    {
        TASK task;   
        task.start_row = i*num_of_rows;
        task.num_of_rows = num_of_rows;
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        tasks[in] = task;  
        in = (in+1)%buff_size;
        pthread_mutex_unlock(&mutex);
        sem_post(&full);
        i++;
        //printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
        if (counter==number_of_tasks)
            break;
    } 

并且......工作线程函数

int i, item, index;
TASK task;
index = *((int*)arg);
int notasks1;
for (i=number_of_tasks; i > 0; i--) {
    //previous code
    sem_wait(&full);
    pthread_mutex_lock(&mutex);
    task=tasks[out];
    out = (out+1)%buff_size;
    //completing task code...
    counter++;
    pthread_mutex_unlock(&mutex);
    sem_post(&empty);
    printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
    if (counter==number_of_tasks)
        break;

}
printf("Worker thread %d has terminated and completed %d tasks\n",index,notasks1);
return NULL;

完整代码......供参考

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include </usr/include/semaphore.h>
// for sleep
#include <unistd.h>
#include "Mandel.h"
#include "draw.h"

#define BUFF_SIZE   10           /* total number of slots */
#define NP          1           /* total number of producers */
#define NC          5           /* total number of consumers */
#define NITERS      IMAGE_HEIGHT/10           /* number of items produced/consumed */

//int buf[BUFF_SIZE];   /* shared var */


//struct task for storing the tasks the current worker thread has to do
typedef struct task 
{
    int start_row;
    int num_of_rows;
} TASK;
TASK* tasks;

int buff_size; //= 7;
//TASK buff[buff_size];
int in=0;               /* buf[in%BUFF_SIZE] is the first empty slot */
int out=0;              /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full;           /* keep track of the number of full spots */
sem_t empty;          /* keep track of the number of empty spots */
int number_of_tasks;// = IMAGE_HEIGHT/20;
float *pixels;
int num_of_rows;// = 20;
int counter = 0;
// use correct type here
pthread_mutex_t mutex;          /* enforce mutual exclusion to shared data */
/*void *Producer(void *arg)
{
    int i =0;
    while (i<number_of_tasks)
    {
        if (counter==number_of_tasks)
            break;
        TASK task;   
        task.start_row = i*num_of_rows;
        task.num_of_rows = num_of_rows;
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        tasks[in] = task;  
        in = (in+1)%buff_size;
        pthread_mutex_unlock(&mutex);
        sem_post(&full);
        i++;
        if (counter==number_of_tasks)
            break;
    }
    return NULL;
}*/

//function for consumer threads to accesss
void *Consumer(void *arg)
{   
    int i, item, index;
    TASK task;
    index = *((int*)arg);//getting index of thread from argument parsing it into int
    int notasks1;
    //for loop to complete number of tasks per thread
    for (i=number_of_tasks; i > 0; i--) {

        //defining start_compute and end compute to calculate time per task 
        struct timespec start_compute, end_compute;
        float difftime;
        printf("Worker(%d): Start the computation ...\n", index);
        clock_gettime(CLOCK_MONOTONIC, &start_compute);
        //calling sem wait to wait for producer thread to fill in tasks for worker threads. will wait if buffer is empty
        sem_wait(&full);
        //calling mutex lock
        pthread_mutex_lock(&mutex);
        //getting tasks from struct tasks array
        task=tasks[out];
        //incrementing to next task in buffer so that next thread accesses next task
        out = (out+1)%buff_size;
        //calculating pixels for image
        int x, y;
        //printf("start_row... %d, num_of_rows... %d\n", task.start_row, task.num_of_rows);
        for (y=task.start_row; y<task.start_row+task.num_of_rows; y++) 
        {
            for (x=0; x<IMAGE_WIDTH; x++) 
            {
                pixels[y*IMAGE_WIDTH+x] = Mandelbrot(x, y);
            }
        }
        //increasing counter to check if all tasks are done
        counter++;
        pthread_mutex_unlock(&mutex);
        sem_post(&empty);//informing a producer that a task has been taken out and if tasks are left buffer is empty to add tasks
        //calculating end compute and posting
        clock_gettime(CLOCK_MONOTONIC, &end_compute); //end time values for the child processes
        difftime = (end_compute.tv_nsec - start_compute.tv_nsec)/1000000.0 + (end_compute.tv_sec - start_compute.tv_sec)*1000.0;
        printf("Worker(%d):\t...completed. Elapse time = %f ms\n",index, difftime);\
        notasks1++;
        printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
        if (counter==number_of_tasks)
            break;

    }
    printf("Worker thread %d has terminated and completed %d tasks\n",index,notasks1);
    return NULL;
}

int main(int argc, char* args[])
{
    buff_size = atoi(args[3]);
    num_of_rows = atoi(args[2]);
    number_of_tasks = IMAGE_HEIGHT/num_of_rows;
    int number_of_workers;
    number_of_workers = atoi(args[1]);
    struct timespec start_time, end_time;
    printf("number_of_tasks...%d\n", number_of_tasks);
    pthread_t idP, idC;
    int index;
    sem_init(&full, 0, 0);//initializing full to zero so that consumer thread knows buffer is empty and waits for producer thread
    sem_init(&empty, 0, buff_size);//initializing empty to buffer size so that producer knows to add that many tasks
    pthread_mutex_init(&mutex, NULL);
    int i = 0;
    pixels = (float *) malloc(sizeof(float) * IMAGE_WIDTH * IMAGE_HEIGHT);//assigning pixels memory
    //tasks = (TASK*) malloc (sizeof(TASK) *buff_size); 
    //pthread_create(&idP, NULL, Producer, NULL);
    for(index=0; index<number_of_workers/*5*/; index++)
    {
        printf("Worker(%d): Start up. Wait for task!\n", index); 
        pthread_create(&idC, NULL, Consumer, (void*)&index);//creating worker threads to go to consumer function sending their index
    }
    tasks = (TASK*) malloc (sizeof(TASK) *buff_size);    
    //master/producer thread work
    while (i<number_of_tasks)
    {
        TASK task;   
        task.start_row = i*num_of_rows;
        task.num_of_rows = num_of_rows;
        //calling sem wait if buffer is not empty
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        //adding tasks to struct task tasks array for worker/consumer threads to use
        tasks[in] = task;  
        in = (in+1)%buff_size;
        pthread_mutex_unlock(&mutex);
        sem_post(&full);
        //incrementing full so that worker threads know that buffer is not empty
        i++;
        //printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
        if (counter==number_of_tasks)
            break;
    }  
    //pthread_exit(NULL);
    //waiting for all threads to exit
    //pthread_join(idC, NULL);  
    //printing image
    printf("Draw the image\n");
    DrawImage(pixels, IMAGE_WIDTH, IMAGE_HEIGHT, "Mandelbrot demo", 3000);

    return 0;
} 

如何阻止工作线程卡在循环中?

我知道程序会继续并显示正确的结果但是当我打电话给pthread_join时,它会继续等待......显然。如何解决这个问题?

0 个答案:

没有答案