C 为什么我的多线程程序有时会阻塞?
我们必须编写一个程序,它有两个线程。其中一个令牌逐个读取内容令牌并将其存储到数组中。另一个从数组中读取令牌并将其写入文件。 代码如下:C 为什么我的多线程程序有时会阻塞?,c,linux,pthreads,mutex,C,Linux,Pthreads,Mutex,我们必须编写一个程序,它有两个线程。其中一个令牌逐个读取内容令牌并将其存储到数组中。另一个从数组中读取令牌并将其写入文件。 代码如下: #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(); i
#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];
}
#包括
#包括
#包括
#定义最大值10
int缓冲区[MAX];
int buf_pos;//缓冲器的实际位置
无效副本();
int标志;//如果标志为0,则读取文件的全部内容
文件*来源;
文件*dest;
//逐个令牌读取文件令牌的内容并将其存储到缓冲区中
void*从_文件()读取_;
//将缓冲区令牌的内容逐个令牌写入文件
void*将_写入_文件();
pthread_cond_t condition=pthread_cond_初始值设定项;
pthread_mutex_t mutex;
int main(int argc,char*argv[])
{
flag=1;
pthread_t writer;
pthread_t读取器;
pthread_mutex_init(&mutex,NULL);
如果(argc!=3)
{
printf(“错误\n”);
退出(退出失败);
}
来源=fopen(argv[1],“r”);
dest=fopen(argv[2],“w”);
if(source==NULL | | dest==NULL)
{
printf(“错误\n”);
退出(退出失败);
}
pthread_create(&reader,NULL,从文件读取,NULL);
pthread_create(&writer,NULL,write_to_file,NULL);
pthread_join(读取器,NULL);
pthread_join(writer,NULL);
}
void*从文件()中读取
{
INTC;
而((c=getc(source))!=EOF)
{
if(buf_pos0)
{
如果(buf_pos>0)//缓冲区不是空的
{
fputc(缓冲区[0],dest);//将第一个令牌写入文件
pthread_mutex_lock(&mutex);
复制();
--布夫波斯;
pthread_mutex_unlock(&mutex);
pthread_cond_信号(&condition);
}
其他的
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&condition,&mutex);
pthread_mutex_unlock(&mutex);
}
}
返回NULL;
}
作废副本()
{
int i=0;
对于(;i
如果我想运行这个程序,它有时会阻塞,但我不知道为什么。但是如果程序终止,输出文件与输入文件相同。
有人能给我解释一下,为什么会发生这种情况吗?代码有很多问题,但锁定的原因很可能是您在没有锁定互斥锁的情况下发送信号,也没有在锁定互斥锁的情况下检查您的状况。这两种方法都是必要的,以确保不会丢失信号 正如无用的注意到的,确保您知道您的共享变量是什么,并且在必要时对它们进行互斥保护。例如,您的
buf_pos
在读卡器线程中没有保护的情况下被修改,并用作两个线程中都没有互斥保护的等待条件
另外,在执行pthread\u cond\u wait
时,您通常需要一个保护表达式,以确保您不会对所谓的spurios唤醒做出反应(请参阅中的“条件等待语义”部分),并确保您等待的条件在测试它和启动等待之间没有实际发生
例如,在writer线程中,您可以执行以下操作:
pthread_mutex_lock(&mutex);
while(buf_pos == 0) pthread_cond_wait(&condition, &mutex);
pthread_mutex_unlock(&mutex);
不过,还是要彻底检查一下您的程序,确定您的共享变量,并确保它们在必要时受到互斥保护。此外,仅为写访问而对共享数据进行互斥保护是远远不正确的。在某些情况下,您可以在读取共享变量时删除互斥保护,但您必须分析代码以确保实际情况属实。代码存在许多问题,但锁定的原因很可能是您在没有锁定互斥的情况下发送信号,并且在锁定互斥锁的情况下不检查您的状态。这两种方法都是必要的,以确保不会丢失信号 正如无用的注意到的,确保您知道您的共享变量是什么,并且在必要时对它们进行互斥保护。例如,您的
buf_pos
在读卡器线程中没有保护的情况下被修改,并用作两个线程中都没有互斥保护的等待条件
另外,在执行pthread\u cond\u wait
时,您通常需要一个保护表达式,以确保您不会对所谓的spurios唤醒做出反应(请参阅中的“条件等待语义”部分),并确保您等待的条件在测试它和启动等待之间没有实际发生
例如,在writer线程中,您可以执行以下操作:
pthread_mutex_lock(&mutex);
while(buf_pos == 0) pthread_cond_wait(&condition, &mutex);
pthread_mutex_unlock(&mutex);
不过,还是要彻底检查一下您的程序,确定您的共享变量,并确保它们在必要时受到互斥保护。此外,仅为写访问而对共享数据进行互斥保护是远远不正确的。在某些情况下,您可以在读取共享变量时删除互斥保护,但您必须分析代码以确保实际情况属实。死锁的问题在于您让两个线程都执行此操作:
pthread_mutex_lock( &mutex );
pthread_cond_wait( &condition, &mutex );
pthread_mutex_unlock( &mutex );
在相同的互斥体和相同的条件变量上。假设您的阅读线程在您的