Fastest i/o in C/C++ language – An important asset for the competitive programming

In C programming all the input-output functions provided under C standard are thread safe. But, POSIX standard provides Multi-thread unsafe functions such as getchar_unlocked(). This method is faster in nature and could be used in the scenarios where we need to have faster IO and we are sure that the resources are not used in the multi-threaded environment.

These methods are of great use in the competitive programming as it happens quite often that the program exceeds the time limit and sometimes it happens by the fractions of seconds. By using these functions for simple IO operations it is possible to skip time issue(if it is actually very less and our logic is also optimized), so it is actually a very important asset in the competitive programming.

What is Thread safe –

Say we’re using multi-threading in our program and, there is some shared space, like a buffer. To avoid race condition, the locking mechanism is used, so as to get a consistent state even if more than one thread is using or manipulating the shared space.
This we study in the operating system as thread synchronization, i.e. when a thread enters a critical section, it acquires a lock( which could be of different types like read lock, write lock etc), so that at a given moment only one thread is in the critical section.
This way we make our resources safe in a multi-threaded environment and it is referred as a Thread safe environment.

Every function such as getchar(), getc(), putchar(), putc(), fgetc() etc. are implemented in thread safe way internally not shown to the programmer. POSIX standard libraries provide locked as well as unlocked IO functions.

  • For lock, the function flockfile()
  • to unlock, the function funlockfile() are used.

Below are the list of some non blocking functions corresponds to blocking function ,

  • getchar_unlocked() -> corresponds to getchar(),
  • getc_unlocked()  – > corresponds to getc(),
  • putchar_uncloked() – > corresponds to putchar()
  • putc_unlocked() – > corresponds to putc()

These are commonly used non blocking i/o functions, there are many others as well, such as fgetc_unlocked(), fputc_unlocked(), fread_unlocked(), fwrite_unlocked(), fgets_unlocked(), getwchar_unlocked() etc.

Non-blocking functions or unlocked functions can be thought as,

flockfile();
ch = getchar_unlocked();
funlockfile();

Above is same as writing just “ch = getchar()”. Hence, it’s now pretty clear that all the non-blocking functions are thread unsafe. Windows library does not provide it.


Advantages of using Non-blocking IO:

Since non-blocking functions do not use any lock checking, thus, these functions are very fast. Also, we know,  getchar() reads a single character of input which is char type whereas scanf() can read most of the primitive types available in c.

So arranging these methods in increasing execution SPEED (Method in the left is faster than it’s right one)
getchar_unlocked() > getchar() > scanf()

Thus, it’s suggested unless speed is not concerned never use these non-blocking functions.
Interestingly, if the program is not multi-threaded then, we could use getchar_unlocked() without any issue. Same for the multi-threaded program also, if we could ensure thread using it is the only thread accessing the object, then also we can use it.


Implementation:

These non-blocking functions implementation is same as its corresponding blocking function. Like use getchar_unlocked() in place of getchar().

See the following example where time taken by both functions is shown,

#include<stdio.h>
#include<time.h>
#define STRINGLENGTH 10

int main(void){
	
        // Using blocking IO
	clock_t begin1 = clock();
	char c1;
	printf("Enter the string of length STRINGLENGTH to check:\n");
	int i = 0;
	while(i++ != STRINGLENGTH)
		c1 = getchar();
	clock_t end1 = clock();
	printf("Time taken by getchar: %f seconds\n", (double)(end1 - begin1)/CLOCKS_PER_SEC);
	
         // Using NON blocking IO
	clock_t begin2 = clock();
	char c2;
	printf("\nEnter the string of length STRINGLENGTH to check:\n");
	int j = 0;
	while(j++ != STRINGLENGTH)
		c2 = getchar_unlocked();
	clock_t end2 = clock();
	printf("Time taken by getchar_unlocked: %f seconds\n", (double)(end2 - begin2)/CLOCKS_PER_SEC);
	
	getchar();
	return 0;
}



Output:-

Enter the string of length STRINGLENGTH to check:
0123456789
Time taken by getchar: 0.000085 seconds

Enter the string of length STRINGLENGTH to check:
0123456789
Time taken by getchar_unlocked: 0.000023 seconds

In the above program, the difference in the time consumed is in terms of microseconds. However, when i/o string becomes larger then, the differences couldn’t be ignored. Check out yourself, change the STRINGLENGTH to your choice in the example. That’s why during online coding competition, coders prefer such non-blocking i/o function.

Knowledge is most useful when liberated and shared. Share this to motivate us to keep writing such online tutorials for free and do comment if anything is missing or wrong or you need any kind of help.
Keep Learning… Happy Learning.. :)