我有以下代码:
/*//not important
FILE * INFILE;
list_file = optarg;
if( ( INFILE = fopen( list_file, "a+" ) ) == NULL ) {
fprintf( stderr, "Can't open input file\n");
exit(0);
}
*/
pthread_mutex_t input_queue;
pthread_mutex_init(&input_queue, NULL);
for( i = 0 ; i < number_thread; i++)
{
if( pthread_create( &thread_id[i], NULL, &work, NULL) != 0 )
{
i--;
fprintf(stderr, RED "\nError in creating thread\n" NONE);
}
}
for( i = 0 ; i < number_thread; i++)
if( pthread_join( thread_id[i], NULL) != 0 )
{
fprintf(stderr, RED "\nError in joining thread\n" NONE);
}
void * work(void * data)
{
unsigned long line;
char buf[512];
while ( !feof(INFILE) )
{
pthread_mutex_lock(&input_queue);
fgets((char *)&buf, sizeof(buf), INFILE);
if (buf[strlen (buf) - 1] == '\n')
buf[strlen (buf) - 1] = '\0';
line = (unsigned long)buf;
pthread_mutex_unlock(&input_queue);
do_work( line );
}
fclose(INFILE);
return NULL;
}
它从文件中读取行但是一段时间后它意外退出,没有错误消息。 我猜我搞砸了。
如何使用pthreads逐行读取文件,但尽可能保持代码不变(我的意思是不要弄乱整个程序)? < / p>
答案 0 :(得分:2)
您在遇到EOF的第一个帖子中关闭INFILE
。之后其他线程将在已关闭的文件上调用feof()
- 可能还有fclose()
- 这将破坏堆并几乎肯定会导致崩溃。此外,您的换行代码可能会在EOF中欠载缓冲区,请参阅下面的注释。
要解决此问题,请使用相同的互斥锁保护feof()
和fclose()
,并将INFILE设置为NULL。获取互斥锁时,检查INFILE是否为NULL并立即返回:
for (;;) {
pthread_mutex_lock(&input_queue);
if (!INFILE) {
pthread_mutex_unlock(&input_queue);
break;
}
if (feof(INFILE)) {
INFILE = NULL;
pthread_mutex_unlock(&input_queue);
break;
}
fgets(buf, sizeof(buf), INFILE);
pthread_mutex_unlock(&input_queue);
// ...strip newline, do_work...
}
几条评论:
您的代码会在不检查buf[strlen(buf) - 1]
是否为零的情况下写入strlen(buf)
。 EOF会buf
为空,所以这不是理论上的问题,每次执行都会发生一次。
line
的类型为unsigned long
,但您要为其指定一个指针值。这将在long
不包含指针的平台上失败,例如Win64。将line
和do_work
的参数声明为char *
(如果必须接受其他指针类型,则为void *
)。
避免将您的互斥锁称为“队列”;在多线程编程队列中引用producer-consumer aware FIFO。
您不需要使用互斥锁保护fgets
之类的各个stdio函数。根据POSIX的要求,它们是MT安全的。 (但是,在我修改过的代码中,fgets()
确实需要受互斥保护,因为INFILE
可能会在未保留互斥锁时失效。)
(char *) &buf
没有意义。由于buf
是char
数组,因此它已经衰减为指向其第一个成员的指针,因此您只需将buf
发送到fgets
即可。如果您坚持使用address-of运算符,则正确的表达式为&buf[0]
。
正如Carl Norum暗示的那样,feof()
可能不是您想要的,因为它只检测fgets()
已经遇到的EOF条件。检查EOF的正确方法是测试fgets()
在剥离换行符之前是否返回空字符串 - 。
答案 1 :(得分:1)
如果INFILE是一个全局变量,那么你已经关闭了线程函数中的参考,如果你创建了多个线程,那么在其他线程中flcose(INFILE),即fclose(NULL)预计会崩溃。无法猜测你试图用多个线程做什么,但最好在你确定INFILE不再被任何其他线程访问时最终关闭它。我认为你应该在所有线程之后关闭主要的INFILE引用加入main并完成他们的处理。
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<stdlib.h>
#define number_thread 10
FILE * INFILE;
char *list_file = "test_thread";
pthread_mutex_t input_queue;
void do_work(unsigned long buf)
{
printf("working on %u\n",buf);
}
void * work(void * data)
{
unsigned long line;
char buf[512];
printf("IAM NEW THREAD\n" );
while ( !feof(INFILE) )
{
pthread_mutex_lock(&input_queue);
fgets((char *)&buf, sizeof(buf), INFILE);
if (buf[strlen (buf) - 1] == '\n')
buf[strlen (buf) - 1] = '\0';
line = (unsigned long)buf;
pthread_mutex_unlock(&input_queue);
do_work( line );
}
return NULL;
}
int main()
{
printf("IAM MAIN THREAD\n")
pthread_mutex_init(&input_queue, NULL);
if( ( INFILE = fopen( list_file, "a+" ) ) == NULL ) {
fprintf( stderr, "Can't open input file\n");
exit(0);
}
pthread_t thread_id[10];
int i=0;
for( i = 0 ; i < number_thread; i++)
{
if( pthread_create( &thread_id[i], NULL, &work, NULL) != 0 )
{
i--;
fprintf(stderr, "\nError in creating thread\n");
}
}
for( i = 0 ; i < number_thread; i++)
if( pthread_join( thread_id[i], NULL) != 0 )
{
fprintf(stderr, "\nError in joining thread\n" );
}
fclose(INFILE);
}