我们必须编写一个程序,它有2个线程。其中一个按令牌读取内容令牌并将它们存储到一个数组中。另一个从数组中读取标记并将其写入文件。 这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX 10
int buffer[MAX];
int buf_pos; // the actual position of the buffer
void copy();
int flag; // if flag is 0, the whole content of the file was read
FILE *source;
FILE *dest;
// read the content of a file token by token and stores it into a buffer
void *read_from_file();
// write the content of a buffer token by token into a file
void *write_to_file();
pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;
int main( int argc, char *argv[] )
{
flag = 1;
pthread_t writer;
pthread_t reader;
pthread_mutex_init( &mutex, NULL );
if( argc != 3 )
{
printf( "Error\n" );
exit( EXIT_FAILURE );
}
source = fopen( argv[1], "r" );
dest = fopen( argv[2], "w" );
if( source == NULL || dest == NULL )
{
printf( "Error\n" );
exit( EXIT_FAILURE );
}
pthread_create( &reader, NULL, read_from_file, NULL );
pthread_create( &writer, NULL, write_to_file, NULL );
pthread_join( reader, NULL );
pthread_join( writer, NULL );
}
void *read_from_file()
{
int c;
while( ( c = getc( source ) ) != EOF )
{
if( buf_pos < MAX - 1 ) // the buffer is not full
{
pthread_mutex_lock( &mutex );
buffer[buf_pos++] = c;
pthread_mutex_unlock( &mutex );
pthread_cond_signal( &condition );
}
else
{
buffer[buf_pos++] = c; // store the last token
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex ); // wait until the other thread sends a signal
pthread_mutex_unlock( &mutex );
}
}
flag = 0; // EOF
return NULL;
}
void *write_to_file()
{
int c;
while( flag || buf_pos > 0 )
{
if( buf_pos > 0 ) // The buffer is not empty
{
fputc( buffer[0], dest ); // write the first token into file
pthread_mutex_lock( &mutex );
copy();
--buf_pos;
pthread_mutex_unlock( &mutex );
pthread_cond_signal( &condition );
}
else
{
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex );
pthread_mutex_unlock( &mutex );
}
}
return NULL;
}
void copy()
{
int i = 0;
for( ; i < buf_pos - 1; ++i )
buffer[i] = buffer[i + 1];
}
如果我想运行该程序,它有时会阻止,但我不知道为什么。但是如果程序终止,则outputfile与inputfile相同。 有人可以解释一下,为什么会发生这种情况?
答案 0 :(得分:3)
代码存在许多问题,但锁定的原因很可能是您在没有锁定互斥锁的情况下发出信号,并且在没有锁定互斥锁的情况下检查您的情况。两者都是必要的,以确保您不会丢失信号。
如无用所述,请确保您知道共享变量是什么,并且必要时它们是互斥保护的。例如,您的buf_pos
在读者线程中被修改后没有保护,并且在两个线程中用作等待而没有互斥保护的条件。
此外,在执行pthread_cond_wait
时,您通常需要一个守护表达式,以确保您不会对所谓的spurios唤醒做出反应(请查看&#34;条件等待语义&#34;在http://linux.die.net/man/3/pthread_cond_wait)部分,并确保您在等待测试之前实际发生的情况并开始等待。
例如,在你的作家帖子中你可以这样做:
pthread_mutex_lock(&mutex);
while(buf_pos == 0) pthread_cond_wait(&condition, &mutex);
pthread_mutex_unlock(&mutex);
但是,请仔细查看您的程序,确定您的共享变量,并确保它们在必要时受到互斥保护。此外,您只需要互斥保护共享数据以进行写访问,这远非正确。在某些情况下,您可以在阅读共享变量时删除互斥保护,但是您必须分析您的代码以确保实际情况如此。
答案 1 :(得分:3)
你的死锁问题是你有两个线程都这样做:
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex );
pthread_mutex_unlock( &mutex );
在相同的互斥锁上,以及相同的条件变量。假设您的读取线程在写入线程之前立即执行这三行。他们都将永远等待相同的条件变量。请记住,如果当时没有线程实际等待它,则发出条件变量的信号。现在你只有当你的一个线程等待那个变量时,你才会避免死锁,如果它偶然发生在它等待它之前发出信号的话。
Sonicwave的答案在识别代码中的其他问题方面做得很好,但总的来说,你对保护共享数据不够小心,而且你没有正确使用条件变量,所以你的线程没有正确同步彼此。除此之外,如果你的一个线程正在等待一个条件变量,你需要确保在另一个线程没有接收到信号并唤醒之前,其他线程不会在相同或不同的线程上等待。