I'm writing a C solution to some variable of the dining savages problem. Now, I create threads which every thread gets a FILE* to the same debug file; inside the thread I'm doing some printing using fprintf(). The printed statements are not protected by any kind of mutex etc..
I don't observe any interleaving behavior in the debug file; it seems that it is thread safe although nowhere online I found a definitive statement that this is the case.
What I did see is the following:
fprintf
is thread safe fprintf
needs to be thread safeThe reason I'm asking that is because this is a university assignment that works, but I still have the doubt that in another windows based computer the program can cause a problem due to the uncertainty discussed above.
I’ll attach the thread code so you will see that the prinintg is not protected:
DWORD WINAPI RoomateThread(LPVOID lpParam) {
/*=================================================
"RoomateThread" this is the roomate thread handler function where
the thread logic is implemented
Input: 1. lpParam holds a roomate, runtime and pointers to both files
Output: 1. return an DWORD value {0}->Success {-1}->Failure
2. A code telling if the run was successful (debug file)
A roommate follows this logic after wake up:
1. If there are clothes available in the closet:
a. Wait for mutex to be available, take it
b. Check if the basket is full
b.1. If it is - start the machine and wait for it to finish
c. Throw an item in the basket
d. release mutex
2. If the closet is empty, wait for laundry_is_empty signal, then goto (1.a)
=================================================*/
/*variable declerations*/
DWORD wait_res, delta;
BOOL release_res;
LONG previous_count;
roomate_thread *elem;
elem = (roomate_thread*)lpParam;
/*thread logic*/
while (TRUE) {
/*calculate the delta between the total run time and the time the roomate had run so far*/
delta = total_time - elem->run_time;
/*wait until the minimum between period Ti and delta*/
Sleep(min(elem->roomate->run_time,delta));
fprintf(elem->debug, "RoomateThread(): Line %d, roomate %d: slept for %d mili sec, starting...\n", __LINE__, elem->roomate->roomate_id, min(elem->roomate->run_time, delta));
/*as instructed, each roomate is active since the wakeup*/
fprintf(elem->report, "\nRoomate %d active", elem->roomate->roomate_id);
/*update the element total run time since start*/
elem->run_time = elem->run_time + min(elem->roomate->run_time, delta);
if (time_to_stop < elem->run_time) {
/*if the element total run time is bigger then the global variable update the global*/
time_to_stop = elem->run_time;
}
/*its time to close the thread properly*/
if (time_to_stop == total_time) {
/*if the laundry basket has clothes in it, and the roomate run as much as the total time
activate rhe robot once more and exit*/
if (elem->run_time == total_time && items_in_laundry!=0) {
release_res = ReleaseSemaphore(
laundry_is_full,
1,
&previous_count);
if (release_res == FALSE) {
fprintf(elem->debug, "MachineThread(): Line %d, released semaphore 'laundry_is_full' failed\nthe last error is: 0X%x\n", __LINE__, GetLastError());
return FAILURE;
}
}
break;
}
/*checks that the roomate has clothes in the closet to continue*/
if (elem->roomate->clothes_in_laundry < elem->roomate->clothes-1) {/*roomate has clothes available*/
fprintf(elem->debug, "RoomateThread(): Line %d, roomate id= %d, number of dirty clothes=%d, number of total dirty clothes=%d\n",__LINE__, elem->roomate->roomate_id, elem->roomate->clothes_in_laundry, items_in_laundry);
}
// It's empty:
else {
/*waits until one of the roomates will activate the robot, cause there is no clothes in the roomate closet*/
fprintf(elem->debug, "DAVIDS roomate %d have no clothes, waiting!!!\n", elem->roomate->roomate_id);
elem->roomate->closet_empty = TRUE;
/*Wait until the machine is done*/
wait_res = WaitForSingleObject(laundry_is_empty, INFINITE);
fprintf(elem->debug, "RoomateThread(): Line %d, roomate %d have clothes,finish waiting!!!\n",__LINE__, elem->roomate->roomate_id);
if (wait_res != WAIT_OBJECT_0) {
fprintf(elem->debug, "RoomateThread() error: Line %d, waiting for sempahore 'laundry_is_empty' failed\nthe last error is: 0X%x\n", __LINE__,GetLastError());
return FAILURE;
}
fprintf(elem->debug, "RoomateThread(): Line %d, laundry_is_empty semaphore aquired , roomate: %d\n", __LINE__,elem->roomate->roomate_id);
}
/* Wait for mutex (machine start and clothes add "rights")*/
wait_res = WaitForSingleObject(mutex, INFINITE);
if (wait_res != WAIT_OBJECT_0) {
fprintf(elem->debug, "RoomateThread() error: Line %d, waiting for 'mutex' failed\nthe last error is: 0X%x\n", __LINE__,GetLastError());
return FAILURE;
}
fprintf(elem->debug, "RoomateThread(): Line %d, mutex aquired , roomate: %d\n", __LINE__, elem->roomate->roomate_id);
fprintf(elem->debug, "RoomateThread(): Line 200, mutex aquired , roomate: %d\n",elem->roomate->roomate_id);
/*Check if basket it full*/
if (items_in_laundry == total_items) {
/*Start Machine*/
release_res = ReleaseSemaphore(
laundry_is_full,
1,
&previous_count);
if (release_res == FALSE) {
fprintf(elem->debug, "MachineThread(): Line %d, released semaphore 'laundry_is_empty' failed\nthe last error is: 0X%x\n", __LINE__, GetLastError());
return FAILURE;
}
fprintf(elem->debug, "RoomateThread(): Line 210, released semaphore 'laundry_is_full' last count is: %ld\n", previous_count);
/*Wait for it to finish*/
wait_res = WaitForSingleObject(laundry_is_empty, INFINITE);
if (wait_res != WAIT_OBJECT_0) {
fprintf(elem->debug, "RoomateThread() error: Line %d, waiting for sempahore 'laundry_is_empty' failed\nthe last error is: 0X%x\n", __LINE__, GetLastError());
return FAILURE;
}
items_in_laundry = 0;
}
/*Throw in a dirty cloth*/
elem->roomate->clothes_in_laundry++;
items_in_laundry++;
/*Release the mutex*/
release_res = ReleaseMutex(mutex);
if (release_res == FALSE) {
fprintf(elem->debug, "RoomateThread(): Line %d, released 'mutex' failed\nthe last error is: 0X%x\n", __LINE__, GetLastError());
return FAILURE;
}
fprintf(elem->debug, "RoomateThread(): Line %d, mutex released , roomate: %d\n", __LINE__, elem->roomate->roomate_id);
}
fprintf(elem->debug, "RoomateThread(): Line %d, thread of roomate %d ended\n", __LINE__, elem->roomate->roomate_id);
return SUCSSES;
}
just reinforming, this runs on windows using visual 2015
will appreciate some help!!!
**in case you will need some more code i will add, although the rest are not that informative to the question asked
C2011 -- the first version of the standard to acknowledge the existence of threads in the first place -- places no limitation on how fprintf()
calls in different threads may or do interact. In that sense, fprintf()
is not thread-safe.
POSIX, however, does specify that fprintf()
calls from different threads of the same process do not interfere with each other, and if that if they both specify the same target file, their output will not be intermingled. POSIX-conforming fprintf()
is thus thread-safe in that sense.
I cannot speak to whether standard C++ places requirements that have the effect of requiring fprintf()
to be thread safe. I would find that surprising, but it could be true. To be sure, it is safe to write to an iostream
object from multiple threads, but that does not imply that the same is true of fprintf()
.
But none of that really matters if you're asking about Windows C or C++, however, which (the C in particular) are well known to be non-conforming. If you want to know about Windows's fprintf()
in particular, then that has already been answered here (yes).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With