Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么我的多线程程序有时会阻塞?_C_Linux_Pthreads_Mutex - Fatal编程技术网

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 ); 
在相同的互斥体和相同的条件变量上。假设您的阅读线程在您的