printf function on multi thread program - c

I'm writing a simple program in c, the program has two threads and two global's var, but the printf function not working, I know that printf is not thread safe and also if I will add \n in the print it will work, but I want to understand why it's not working without that?
I'm adding the code,
#include <pthread.h>
#include <stdio.h>
int i;
int j;
void* runi(void* _temp)
{
while(1)
{
i++;
if(i==1000)
{
printf("i: %d",i);
}
}
return NULL;
}
void* runj(void* _temp)
{
while(1)
{
j++;
if(j==1000)
{
printf("j: %d",j);
}
}
return NULL;
}
main ()
{
pthread_t threadI,threadJ;
pthread_create(&threadI,NULL,runi,NULL);
pthread_create(&threadJ,NULL,runj,NULL);
pthread_join(threadI,NULL);
pthread_join(threadJ,NULL);
return 0;
}

printf is somehow thread safe* (see discussion in unlocked_stdio(3)..., and consider flockfile(3)) but stdio is buffered, and you should call fflush(3) in your routines.
(printf is perhaps thread safe because two concurrent printf might not intermix their output, but nothing is told about flushing buffers)
So code instead
if(i==1000) {
printf("i: %d",i);
fflush(stdout);
}
(then you'll see some output)
BTW, I recommend ending most of your printf format control strings with a newline \n.... You could also add some delay by doing some nanosleep(2) or usleep(3) in your runi & runj routines.
It is the buffering which explains that you are disappointed. And stdout should be buffered for efficiency reasons (see setvbuf(3)...). Be aware that system calls (listed in syscalls(2) for Linux) such as write(2) are quite expensive operations. On Linux use strace(1) to understand what system calls are done.
If you want to understand the implementation of printf on Linux, study the source code of your C standard library - which is free software. It probably is GNU glibc, but could be something else like musl-libc, etc.
BTW, your threads are never ending (since runi and runj never return), and you pthread_join them. That call is blocking indefinitely. Use ltrace(1) to observe that.
You could also consider adding some sleep(2); fflush(stdout); in your main before the first pthread_join; you'll then observe some output.
At last, for such experiments, I recommend some periodic printing. Replace the i==1000 condition by i%10000 == 0 ....
You never explicitly flush your stdout so its gets flushed when its buffer (perhaps 8Kbytes) is full, or at end of your main (which is not reached in your case). Jonathan Leffler cleverly commented that you might need to wait an hour for that (buffer full condition) to happen.
Beware of race conditions and of undefined behavior.

Related

Interesting glitch-like behavior when testing SIGINT and SIGHUP on linux

Lately have been testing out using signals such as SIGINT and SIGHUP and their role on ongoing processes on Linux. Running the following code returned some interesting results.
#include <signal.h>
#include <stdio.h>
void routine(int p){
puts("Not finishing");
sleep(2);
}
main(){
int i = 0;
signal(SIGINT, routine);
signal(SIGHUP, routine);
while(1){
printf("%d \n", i++);
}
}
As you can see, it simply counts from 0 on an infinite loop. Then, by using kill -SIGINT on the process it created, I got the following:
Routine
As you can see, before the line I requested the routine to print, the program repeated the last number (and it does not happen always). I would really like to know why.
It is likely that you are narrowly avoiding horrible bugs by accident.
What I think is happening is that the signal sometimes interrupts while printf is in progress formatting the string into the output buffer. Then the puts in the signal handler inserts more string into the output buffer. Then the handler returns, printf inserts the newline and flushes the buffer.
But guess what would happen if this signal occurred just before the flush of a full 8K output buffer. The buffer positions would be at the end. Then the puts call happens, not realizing that printf is already in process of flushing and clearing the buffer. Where exactly would it be putting the puts string? At the beginning? At the end? Would the excess data printf was in the process of writing write over the string that puts had added? All of those things are possible.
Buffered C output is not reentrant and cannot be used in signal handlers.

Why does alarm() cause fgets() to stop waiting?

I am playing around with signals in C. My main function basically asks for some input using fgets(name, 30, stdin), and then sits there and waits. I set an alarm with alarm(3), and I reassigned SIGALRM to call a function myalarm that simply calls system("say PAY ATTENTION"). But after the alarm goes off, fgets() stops waiting for input and my main fn continues on. This happens even if I change myalarm to just set some variable and do nothing with it.
void myalarm(int sig) {
//system("say PAY ATTENTION");
int x = 0;
}
int catch_signal(int sig, void (*handler)(int)) { // when a signal comes in, "catch" it and "handle it" in the way you want
struct sigaction action; // create a new sigaction
action.sa_handler = handler; // set it's sa_handler attribute to the function specified in the header
sigemptyset(&action.sa_mask); // "turn all the signals in the sa_mask off?" "set the sa_mask to contian no signals, i.e. nothing is masked?"
action.sa_flags = 0; // not sure, looks like we aren't using any of the available flags, whatever they may be
return sigaction(sig, &action, NULL); // here is where you actually reassign- now when sig is received, it'll do what action tells it
}
int main() {
if(catch_signal(SIGINT, diediedie)== -1) {
fprintf(stderr, "Can't map the SIGINT handler");
exit(2);
}
if(catch_signal(SIGALRM, myalarm) == -1) {
fprintf(stderr, "Can't map the SIGALAM handler\n");
exit(2);
}
alarm(3);
char name[30];
printf("Enter your name: ");
fgets(name, 30, stdin);
printf("Hello, %s\n", name);
return 0;
}
Why does alarm() make fgets() stop waiting for input?
Edit: Added code for my catch_signal function, and, as per one of the comments, used sigaction instead of signal, but the issue persisted.
The answer is most likely going to be OS/system specific.
(As stated by Retr0spectrum) The fgets() function often makes system calls, such as read(). System calls can terminate if a signal is detected. In the case of this question, the fgets() function has made a system call (likely the read() system call) to read a character from stdin. The SIGALRM causes the system call to terminate, and set errno to EINTR. This also causes the fgets() function to terminate, without reading any characters.
This is not unusual. It's just how the OS implements signals.
To avoid this problem, I will often wrap fgets() function in a loop like this:
do {
errno=0;
fgets(name, 30, stdin);
} while(EINTR == errno);
It will require that you: #include <stdio.h>
(As suggested by TonyB).
As to the question of why the alarm signal interrupts the read, there are two reasons:
It's the way Unix used to do it, and it was because it was much easier to implement in the OS. (On the one hand this sounds kind of lame, but the "don't sweat the hard stuff" attitude was responsible in part for the success of Unix in the first place. This is the topic of Richard P. Gabriel's epic Worse Is Better essay.)
It makes it easy to implement a read that times out and gives up, if that's what you want. (See my answer to this other question.)
But, as other comments and answers discuss, the interrupting behavior is somewhat obsolete; most modern systems (Unix and Linux, at least) now automatically restart an interrupted system call such as read, more or less as you were wishing. (Also as pointed out elsewhere, if you know what you're doing you may be able to select between the two behaviors.)
In the end, though, it's a grey area; I'm pretty sure the C standard leaves it unspecified or implementation-defined or undefined what happens if you interrupt a system call with an alarm or other signal.

handle SIGINT with scanf in loop

I have to take input from user in a while loop and then take some action. And I also want to exit my code on ctrl+c input.
void my_signal_handler(int sig)
{
running = false;
signal(sig, SIG_IGN);
}
int main(void)
{
struct sigaction sa = {{0}};
sa.sa_handler = &my_signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGINT, &sa, NULL) != 0)
{
fprintf(stderr, "sigaction error\n");
return -1;
}
while(running)
{
printf("enter number: ");
scanf("%d", &num);
// take action based on number
}
}
Problem with this code is after pressing ctrl+c, it doesn't exit but it waits for input for scanf. So once I press an extra key, the program exits (signal handler gets called).
How can I remove this extra step of giving input to scanf after pressing ctrl+c ?
You should install the signal handler. At the very least, add
signal(SIGINT, my_signal_handler);
inside your main before the while(running), but better use sigaction(2).
You should also know that stdio is buffering; usually stdout is line-buffered when it is a terminal (but see setvbuf(3) and friends). So you should either call fflush(3) (probably as fflush(NULL);) before the scanf inside the loop, or terminate every printf format control string with an explicit \n.
At last, scanf(3) can fail and is returning the count of scanned items, which you should test.
BTW, your  main is wrong, should be defined as int main(void) or preferably int main(int argc, char**argv).
However (assuming you are on Linux), read very carefully signal(7) (notice what is said about signal handlers and async-signal safe functions) and POSIX signal.h documentation and declare your running flag as
volatile sigatomic_t running;
(or perhaps, in C11, as volatile _Atomic bool running;)
The volatile qualifier is very important. Otherwise, the compiler is allowed to optimize (and e.g. pretend that running is always true).
Notice that using signal(2) is often a bad idea. First, if you really need signal handling, you'll better use sigaction(2). Then your call to signal(sig, SIG_IGN); is, in your case, useless (since the running volatile flag would have been changed in the signal handler). At last, for multiplexing input (& output), you could use poll(2) which can be used to wait and test if there is some available input on stdin (actually STDIN_FILENO which is 0), and more generally to implement event loops. You could use (instead of poll which I strongly recommend) the old and nearly obsolete select(2), but you'll rather use poll(2). See also epoll(7) & inotify(7) but you probably don't need them.
Be aware that in terminals, stdin is often a tty (check that with isatty(3)) following the line discipline (so some of the line buffering happens inside the kernel). Read the tty demystified page. Consider using the GNU readline library and function (or perhaps ncurses), which might be what you really need.
Read also Advanced Linux Programming and take the habit of reading the documentation of every function that you are using.

Why is the line following printf(), a call to sleep(), executed before anything is printed?

I thought I was doing something simple here, but C decided to go asynchronous on me. I'm not sure what's going on. Here's my code:
#include <stdio.h>
int main() {
printf("start");
sleep(5);
printf("stop");
}
When I compile and run, I notice that sleep(5) works like a charm. But the compiler decided it was a good idea to skip the first printf() and go out of order, so when running, the program waits for 5 seconds and then prints startstop.
What's the deal? My theory is that the program initiates the print operation with the shell, then continues with the program, leaving Bash to wait until the program is no longer busy to actually render the strings. But I really don't know.
Thanks
printf uses buffered output. This means that data first accumulates in a memory buffer before it is flushed to the output source, which in this case is stdout (which generally defaults to console output). Use fflush after your first printf statement to force it to flush the buffered data to the output source.
#include <stdio.h>
int main() {
printf("start");
fflush(stdout);
sleep(5);
printf("stop");
}
Also see Why does printf not flush after the call unless a newline is in the format string?
Try adding '\n' to your printf statements, like so:
#include <stdio.h>
int main() {
printf("start\n");
sleep(5);
printf("stop\n");
}
The compiler is not executing this out of order. Just the output is getting accumulated, and then displayed when the program exits. The '\n' will invoke the line discipline in the tty drivers to flush the output.
Read this Q&A, it explains it.

Why do I have different output between a terminal and a file when forking?

I'm learning to work with fork(), and I have some questions.
Consider the following code:
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
for(i = 0; i < 5; i++)
{
printf("%d", i);
if((i%2)==0)
if(fork())
fork();
}
}
When I output to a terminal, I get the result I expect (i.e.: 0,1,1,1,2,2,2,...). But when I output to a file, the result is completely different:
Case 1: (output to terminal, e.g.: ./a.out):
Result is: 0,1,1,1,2,2,2,...
Case 2: (output to file, e.g.: ./a.out > output_file)
Result is: 0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,...
Why it is like this?
When you output to a file, the stdio library automatically block-buffers the outbound bits.
When a program calls exit(2) or returns from main(), any remaining buffered bits are flushed.
In a program like this that doesn't generate much output, all of the I/O will occur after the return from main(), when the destination is not a tty. This will often change the pattern and order of I/O operations all by itself.
In this case, the result is further complicated by the series of fork() calls. This will duplicate the partially filled and as-yet-unflushed I/O buffers in each child image.
Before a program calls fork(), one might first flush I/O using fflush(3). If this flush is not done, then you may want all processes except one (typically: the children) to _exit(2) instead of exit(3) or return from main(), to prevent the same bits from being output more than once. (_exit(2) just does the exit system call.)
The fork() inside if block in your program is executed twice, because once fork is successful, the program is controlled by two processes(child and parent processes).So fork() inside if block, is executed by both child and parent processes. So it will have different output than expected since it is controlled by two different process and their order of execution is not known. ie. either child or parent may execute first after each fork()
For the difference in behaviour between the output and the file. this is the reason.
The contents you write to the buffer(to be written to file(disk) eventually) is not guaranteed to be written to the file (disk) immediatley. It is mostly flushed to the disk only after the execution of main() is complete. Whereas, it is output to terminal, during the execution of main().
Before writing to file in disk, the kernel actually copies the data into a buffer and later in the background, the kernel gathers up all of the dirty buffers, sorts them optimally and writes them out to file(disk).This is called writeback. It also allows the kernel to defer writes to more idle periods and batch many writes together.
To avoid such behaviour, it is always good to have three different condition checks in program using fork()
int pid;
if((pid = fork()) == -1 )
{ //fork unsuccessful
}
else if ( pid > 0)
{ //This is parent
}
else
{//This is child
}
buffered streams can produce some strange results sometimes... especially when you have multiple processes using the same buffered stream. Force the buffer to be flushed and you'll see different results:
int main()
{
int i;
FILE * fd = fopen(yourfile, "w");
for(i = 0; i < 5; i++)
{
fprintf(fd, "%d", i);
fflush(fd);
if((i%2)==0)
if(fork())
fork();
}
}
Also, for your debugging purposes, it might be nice to dump the process' IDs so you can see which process spawns which, and have a better idea of what's going on. getpid() can help you with that.
Why do I have different output between a terminal and a file when
forking?
C standard library functions use internal buffering for speed up. Most implementations use fully buffered IO for file streams, line buffered for stdin/stdout and unbuffered for stderr.
So your problem can be solved in number of ways:
Use explicit buffer flush before fork via fflush(3)
Set buffer type manually via setvbuf(3)
Use write(2) instead of stdlib's printf(3)
Output to stderr by default via fprintf(3) *****
Exit with _exit(2) in forked processes instead of exit(3) ******
Last two may not work as expected if:
* your implementation does not use unbuffered writes to stderr by default (Which is required by ISO C)
** you have written more than default buffer size in child and if was automatically flushed.
PS. Yet again, if you need deeper knowledge of standard library functions and buffering I recommend reading Advanced Programming in the UNIX Environment (2nd Edition) by W. Richard Stevens and Stephen A. Rago.
PPS. btw, your question is a very popular interview question for C/C++ programmer position.

Resources