You are closing INFILE
in the first thread that encounters EOF. Afterwards other threads will call feof()
— and possibly fclose()
— on the closed file, which will corrupt the heap and almost certainly lead to a crash. Also, your newline-chopping code can underrun your buffer at EOF, see remark below.
To fix the problem, protect feof()
and fclose()
with the same mutex, and set INFILE to NULL. When the mutex is acquired, check for INFILE being NULL and return immediately if so:
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...
}
Several remarks:
your code writes to
buf[strlen(buf) - 1]
without checking whetherstrlen(buf)
is zero.buf
will be empty at EOF, so this is not a theoretical concern, it will happen exactly once in every execution.line
is of typeunsigned long
, but you are assigning it a pointer value. This will fail on platforms wherelong
does not contain a pointer, such as Win64. Declareline
and the argument ofdo_work
aschar *
(orvoid *
if it must accept other pointer types) instead.avoid calling your mutex a "queue"; in multithreaded programming queue refers to a producer-consumer aware FIFO.
you don't need to protect individual stdio functions like
fgets
with mutexes. They are MT-safe, as mandated by POSIX. (However, in my modified code,fgets()
does need to be mutex-protected becauseINFILE
can become invalidated while the mutex is not being held.)(char *) &buf
doesn't make sense. Sincebuf
is achar
array, it already decays to a pointer to its first member, so you can simply sendbuf
tofgets
. If you insist on using the address-of operator, the correct expression is&buf[0]
.as Carl Norum hinted,
feof()
is probably not what you want, since it only detects EOF condition already encountered byfgets()
. The correct way to check for EOF is by testing whetherfgets()
returns an empty string — before stripping the newline.