无法弄清楚为什么我不从一个线程获取作为输入的数组并尝试使用另一个线程打印它

时间:2019-04-03 14:00:18

标签: c linux pthreads

#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex;
pthread_cond_t cond;
void *producer(void *arg);
void *consumer(void *arg);
int buffer[100];
static int n;

void *producer(void *arg) {   //`For taking user input`
int i;
printf("\n Enter the Array of %d terms",n);

for (i = 0; i < n; i++) 
{
 pthread_mutex_lock(&mutex);
 scanf(" %d\n",&buffer[i]);

 pthread_cond_signal(&cond);
 pthread_mutex_unlock(&mutex);
}
}

void *consumer(void *arg) {  // For printing the input array
int i;

printf("\nConsumer Function"); 
pthread_mutex_lock(&mutex);
for (i = 0; i < n; i++) 
{

printf("%d\n",buffer[i]);         
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);

}
}

int main()
{
int i=0;
pthread_mutex_init(&mutex, 0);
pthread_cond_init(&cond, 0);

pthread_t pThread, cThread;

printf("\n Enter no of terms");
scanf("%d",&n);

pthread_create(&pThread, 0, producer, 0);
pthread_join(pThread,NULL);  
pthread_create(&cThread, 0, consumer,0);   
pthread_join(cThread, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}

在生产者函数中,借助线程(pThread),我获取了用户对数组的输入,然后尝试在cThread的消费者函数中打印相同的数组。但是我只能打印数组的第一个元素。我需要进行哪些更改才能使整个数组作为输出?

1 个答案:

答案 0 :(得分:0)

您的问题的答案是,在创建新线程之前,您正在为线程执行pthread_join()。这意味着您要在开始新线程之前退出第一个线程。因此,所有操作都是完全串行的。

您应该启动两个线程,然后按如下所示加入它们。

pthread_create(&pThread, 0, producer, 0); //Check return value and handle error
pthread_create(&cThread, 0, consumer,0);  //Check return value and handle error  
pthread_join(pThread,NULL);
pthread_join(cThread, NULL);

但是您的代码中还有另外一个问题。在Consumer()函数中,您将解锁for循环内的互斥量。我假设,您希望用户从生产者线程中读取用户的一项输入,并在消费者线程中打印该输入值。在这种情况下,您必须将互斥锁解锁调用移到循环之外。请注意,pthread_cond_wait()将在等待期间内部解锁互斥锁。另外,您需要在pthread_cond_wait()之后打印值,以确保用户输入了输入值。

pthread_mutex_lock(&mutex);
for (i = 0; i < n; i++) 
{
    pthread_cond_wait(&cond, &mutex);
    printf("%d\n",buffer[i]);    
}
pthread_mutex_unlock(&mutex);

我为下面有趣的部分写了这个答案!

调用pthread_create();对于一个线程并不意味着该线程立即开始运行。多个线程可以按随机(应假定)顺序运行。

所以..如果使用者线程启动得很晚,即如果它在生产者线程中两次或更多次pthread_cond_signal(&cond);之后启动,那么使用者线程将进入死锁状态,因为它确实执行了n个pthread_cond_wait()调用。请注意,如果没有线程在那个确切的时间执行pthread_cond_signal(),那么将丢失pthread_cond_wait()

所以..您需要确保使用者线程已经启动,然后才开始从生产者线程读取输入。

有多种方法可以实现这一目标。一种方法是使用全局标志和互斥进行轮询。 (您可以为此使用其他互斥条件信号组合。)

void *producer(void *arg) { 
    while(1) {
        pthread_mutex_lock(&mutex);
        if(1 == consumerStartedFlag) {
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_mutex_unlock(&mutex);
        usleep(1000); //Sleep for 1ms to prevent this thread from consuming large CPU
    }

    //Rest of the producer functionality
}


void *consumer(void *arg) {  // For printing the input array

    pthread_mutex_lock(&mutex);
    consumerStartedFlag = 1; //Global flag, intialize it to zero in main before starting threads.
    pthread_mutex_unlock(&mutex);

    //Rest of the consumer functionality
}

现在,如果生产者首先启动,它将在while循环中等待。如果使用者先开始,它将在pthread_cond_wait()中等待。

更新1 根据以下评论。

在producer()中,scanf()位于互斥锁内。它将无限期地阻止消费者。因此,您可能无法正确获得输出。因此,将scanf()放在外部锁如下,

 scanf(" %d",&buffer[i]); //Remove '\n' from scanf() as it will block your scanf call.
 pthread_mutex_lock(&mutex);
 pthread_cond_signal(&cond);
 pthread_mutex_unlock(&mutex);