Linux/Unix

Multiple child processes (Recursive-fork)




     A simple recursive code to demonstrate how, a fork command can be invoked into a function, that may call the fork till arguments reach the end, with a tree that would work, printing the buffer with command line arguments. It happens to print in a specific order, from the end to the start without an exit(0) function.


___________________________________________________________________________________



Use of 'endl' in a 'Cout' Stream for 'dup2'



In the line after duplicating the file descriptor of 'fileP[1]' with the standard output, the next line of printing a buffer using the 'cout' object, is basically a function call, where the 'buffer' is printed. The reason to use endl, even though we are not printing to the terminal, is because 'endl' happens to flush the output stream which is good practice in itself. A much better method could be to use the cout.flush(), as both perform the same tasks only with 'endl' adding a newspace in itself. In common practice, this might be overlooked, but may present an error when encountered as in a case of duplicating and writing a buffer to a pipe.  

Cases of Flushing:





___________________________________________________________________________________



A case of 'named pipe' exception


Server Side.c

Client Side.c

During a recent program I tried to make in C, this time, with a named pipe, that for starters, is basically like a FIFO file with an entry in a file system that isn't there but just a reference in a file-system (with a nice name), I stumbled upon an exception, where after a certain period of time, if left running, the Server Side ends up in a continuous loop, and is unable to block from it's side (a.k.a wait for the Client to write the bytes into the pipe). Continuous execution by gcc-compiling and running the .out file in split terminal, doesn't help, until you happen to call the unlink() function in the ClientSide.c, that removes the entry. And upon execution again, they happen to run perfectly.

What does Unlink() do?

Unlink() happens to remove the file object from the filesystem, so that it goes away, like an unnamed pipe. However, the case that happened to cause this was:

Once a pipe has been created, another attempt to create would result in an error, basically an error that would point that the file already exists, and that would happen to either (a) stuck the program or (b) cause an evil loop, if there is one and the program somehow skips the error.
The unlink() managed to remove the pipe so that the next launch would create the FIFO obj again, hence the proper working. I am still, doubtful of the circumstances under which this happened to take place, and if another such exception throws up, a diagnosis to carry out the possible causes will be listed in this again.


___________________________________________________________________________________


Using 'mmap' in shared memory


The code given above is a simple demonstration of using 'mmap' to map some content onto virtual memory space. Let's clarify this a bit more:

  • The file descriptor opens the file
  • The mmap() is called with the length of this file in the second parameter and the offset '0' in the last, basically the beginning of the file
  • The contents are mapped for this length and a pointer to this is returned

  • As seen, the pointer is a char*, which can be manipulated by indexes like a buffer to read the content or just use it
  • In a client-server communication model, this pointer can be shared by 'shared memory loc'
  • At the end, munmap() tends to delete the mappings
I didn't run into any errors during this, thus I haven't specified any here, as is routine. But, here are a few findings I'll enlist below:

  • Mmap() is faster than system calls due to less context-switching (kernel to user, vice versa), and as stated by another user, due to vector type memory allocation.
  • Mmap() uses page-sizes or, let's say, it uses the multiples of this, to make finding content easier. Let's say, we have page sizes starting from '0' to '4' to '8' to '12' to '16', which are all multiples of '4', thus one page here is, assumed, 4kB, so now, if I were to map files at an offset corresponding to these multiples, it would be easy to find it, and read out the data. Once again, if the length is bigger than a page size, it is mapped out on several pages which brings us to the last point
  • Slack Space is an issue for smaller sizes 


___________________________________________________________________________________


Why is pthread_join() important?


I recently carried out an experiment while working with pthreads in C, and found out that not using pthread_join() led to a failure in achieving desired results. Here is the experiment with socket-connections while working in Linux:


The output came out to be that the 'func' skipped its print statements and ended up only printing the 'before pthread() join' and 'after pthread() join'. However, when pthread_join() was called, the results came out fine. 

Here is the func:



The pthread_join() tends to wait for the thread to finish its work. Meaning, that the thread will first execute all its statements and then return back to the main(), for it to continue execution after it's previous statements. 
There is a concept of deferred cancellation, an orderly cancel method for a thread or process to die. Deferred means to postpone, and basically, what it does is: A process may have a call in some other process for its cancellation, however, the call will only succeed, once a flag has been set by the process that has to be cancelled, that it should be cancelled. Process 2 may have a call for Process 1 cancellation, however, it will only execute the cancel call, once Process 1 sets the flag for its kill. 


___________________________________________________________________________________


The 'barrier_problem' solution


My solution to the barrier problem, uses a counting semaphore for the barrier, in order for it to be decremented accordingly to the number of calls for threads. So if for example, there are '5' threads, starting from '0' to '4', the barrier will be posted in a loop 5 times, till '4', decremented by '1' each time for the thread, surpassing the wait call and in the end returning to the main as '0'.

___________________________________________________________________________________


'Multi-level' indexed allocation Visual Example



What does the above mean? We are given the following requirements:

  • Each block has a space of 4096 bytes
  • The blocks can have data blocks and index blocks
  • There are two levels of indexes, and our choice is to store 1024 4 -byte pointers in each 4096 byte index blocks, why? Because 1024*4 = 4096. Thus we store the pointers in this way.

What does a pointer do? It simply points to the data block. And it is stored in a similar block, called an index block. So two levels of indexes basically mean, that each pointer in the first level (the first index block - which specified above has a total of 1024 pointers) points to other index blocks (each of once again, 1024 blocks). Meaning we now have 1024*1024 = 1,048,576 pointers, pointing to data blocks, so a total of 1,048,576 data blocks.

Now we were said, that each block has a space of 4096 bytes, right! So if we have 1,048,576 data blocks, then we have exactly the space of 1,048,576 * 4096 bytes = 4,294,967,296 bytes that are equals to 4 GB. Hence that's how, multilevel indexing works. 











 

Comments