brain teaser: file sharing by an application and its child(s)

  • 12 years ago

    Hi guys,

    I have got something to test your understanding of  multitasking processes.  Have a fun!!

    An application opens a file and starts a child process passing the file handle to the child.  The application(parent)  and its child share the file.  When these two processes write to or read the file, a big problem can occur if they do not snychronise their wirting and reading of the file!!  Why?

    Try the following example programs (testp.cpp & testc.cpp).  Run testp.exe and observe the problem!!

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    // testp.cpp : the parent application
    //
    // When running, this program prints the following to the screen:
    //  End of the child
    //  child*
    //  parent
    //  Parent: exiting
    //
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <process.h>
    #include <windows.h>  // for Sleep( )
    #include <winbase.h>  // for Sleep( )
    //#include <winnt.h>  // For SECURITY_ATTRIBUTES

    #define len_of_record  6  // for length of a record in the file
    #define filename  "test.txt"  // our database file

    int main( )
    {

     char buf[100]; unsigned long nbytes;

     HANDLE filehandle;
     char filehandle_str[20];
     int err;

     SECURITY_ATTRIBUTES sa;  // For CreateProcess( ) & CreateFile( )

     // For the file handle to be inherited by a child
     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
     sa.lpSecurityDescriptor = NULL;
     sa.bInheritHandle = TRUE; // We want the file to be inherited by a child

     // *** Open our database file ***
     // Note the file attributes flag FILE_FLAG_WRITE_THROUGH|FILE_FLAG_RANDOM_ACCESS
     // to avoid lazy flush when writing to the disk.
     if ((filehandle=CreateFile(filename,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|
       FILE_SHARE_WRITE,&sa,OPEN_ALWAYS,FILE_FLAG_WRITE_THROUGH|
       FILE_FLAG_RANDOM_ACCESS,NULL)) ==
       INVALID_HANDLE_VALUE ) {
      // an error to open the file. we have to terminate this session
      fprintf(stderr,"Fatal(parent):failed to open our database file %s",filename);
      Sleep(5000);
      exit(3);
     } // if

     // We could use either CreateProcess( ) or spwanlp( ) to 
     // start/create a child.                                

     itoa((int)filehandle, filehandle_str, 10);

     // Create the child using spawnlp( )
     if (spawnlp(P_NOWAIT,"testc.exe","testc.exe",filehandle_str,NULL)==-1){
      // Error: failed to create a child process
      fprintf(stderr,"Fatal: failed with CreateProcess( )\n");
      fprintf(stderr,"Parent exits\n");
      Sleep(4000); // To keep the output window open for 4 secs
      exit(1);
     } // if

     // Set the file pointer to the beginning of the file
     if (SetFilePointer(filehandle,(LONG)0,(PLONG)NULL,FILE_BEGIN)
      == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
      CloseHandle(filehandle);
      printf("Fatal(parent): SetFilePointer() failed\n");
      Sleep(10000);
      exit(2);
     } // if

     Sleep(2000); // Give the child enough time to exit!

     // Write "parent" into the beginning of the file!
     strcpy(buf,"parent");  //note strlen(buf) = len_of_record!
     if (WriteFile(filehandle,buf,len_of_record,&nbytes,NULL) == 0 ||
      nbytes != len_of_record) {
      printf("Parent: error for WriteFile()=%d\n",err=GetLastError());
      CloseHandle(filehandle);
      Sleep(5000);
      exit(4);
     } // if 


     // *** We now read the records from the file ***

     // Read the records from the file & print them to the screen
     // Note that the position # of the 1st byte in a file is 0(zero), not 1.

     if (SetFilePointer(filehandle,(LONG)0,(PLONG)NULL,FILE_BEGIN)
      == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
      CloseHandle(filehandle);
      printf("Fatal(parent): SetFilePointer() failed\n");
      Sleep(10000);
      exit(2);
     } // if

     while (1) {
      if (ReadFile(filehandle,buf,len_of_record,&nbytes,NULL) == 0) {
       printf("Parent: error for ReadFile()=%d\n",err=GetLastError());
       CloseHandle(filehandle);
       Sleep(5000);
       exit(4);
      } else if (nbytes == 0) {
       // end of file reached
       break;
      }// if & else if
      buf[len_of_record] = '\0';
      printf("%s\n",buf);
     } // while

     _flushall();

     CloseHandle(filehandle); // This does not affect the file open for the child
     printf("Parent: exiting\n");
     Sleep(20000); // Sleep for 20 seconds
    }  // main


    // testc.cpp :the child application

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    #include <io.h>
    #include <windows.h>  // For Sleep( )
    #include <winbase.h>  // For Sleep( )

    #define  len_of_record 6  // a record is 6 chars long
    #define  filename        "test.txt" // our database file


    int main(int argc, char **argv)
    {

     char buf[len_of_record+1]; // buf to write to the file
     unsigned long nbytes;    // # of bytes written to or read from the file
     HANDLE filehandle;      // for our database file (opened for the parent too)
      
     filehandle = (HANDLE) atoi(argv[1]);  // file handle inherited from the parent


     // write "child*" to the beginning of the file
     strcpy(buf,"child*"); // note strlen(buf) = 6!
     if (SetFilePointer(filehandle,0,(PLONG)0,FILE_BEGIN)==0xFFFFFFFF ){
      CloseHandle(filehandle);
      printf("child: SetFilePointer() failed\n");
      Sleep(5000);
      exit(2);
     } // if

     if (WriteFile(filehandle,buf,len_of_record,&nbytes,NULL)==0){
      printf("child: WriteFile() failed\n");
      printf("            error = %d\n",GetLastError()); //c.f. ERROR_LOCK_VIOLATION=33
      CloseHandle(filehandle);
      Sleep(20000);
      exit(4);
     } // if
     

     printf("End of the child\n");
     CloseHandle(filehandle);
    } // main
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Post a reply

No one has replied yet! Why not be the first?

Sign in or Join us (it's free).

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“In theory, theory and practice are the same. In practice, they're not.”