0

I have a file which will be read and write by the multiple process. So to synchronize the file between multiple processes I was using fcntl().

Let's assume we have a file orignal.txt and we have some content in the orignal.txt. Assume the contents in the file are:

show core status
show table status
show action status

Now let's say we have three process A,B,C which would be accessing orignal.txt for deleting the content from it. Say A will delete show core status. B will delete show table status and C will delete show action status.

Actually show core status,show table status and show action status are some commands which is related to particular process, So I am assuming show core status is related to A so whenever A will come he will write show core status into the file orignal.txtand before A terminates it will delete the show core status from the file orignal.txt. Same with other processes also. So for that I have written the code.

Note: This is a common API for deleting the content from the file which all three processes (A,B,C) will use.

#define ACQUIRE_LOCK 1
#define RELEASE_LOCK 0    
int delete_content_from_file(char *command)
{
    FILE *fp, *tempFd;
    char buf[4096];
    int ret;
    fp = fopen ("orignal.txt", "r+");
    if (fp == NULL)
    {
        printf("orignal.txt does not exist");
        return -1;
    }

    printf("Acquiring lock for orignal.txt");
    ret = fileSync(fp,ACQUIRE_LOCK,F_WRLCK);
    if(ret == -1)
    {
    printf("Failed to acquire lock");
    exit(EXIT_FAILURE);
    }
    tempFd = fopen ("duplicate.txt", "w");
    if (tempFd == NULL)
    {
       printf("Duplicate.txt not exist");
       return -1;
    }

    // read text until newline
    while (!feof(fp))
    {
        if (fgets (buf, sizeof(buf), fp) != NULL)
        {
            buf[strlen(buf)-1]='\0';

            if ((ret = strcmp (command, buf)) != 0) {
            fprintf(tempFd, "%s\n", buf);
        }
    }

fclose(tempFd);
system("cp duplicate.txt orignal.txt");
remove("duplicate.txt");
printf("Releasing lock");
ret = fileSync(fp,RELEASE_LOCK,F_UNLCK);
if(ret == -1)
{
    printf("unable to release the lock for orignal.txt");
    return -1;
}
fclose (fp);
return 0;
}

int fileSync(FILE *fd,bool flag,short lock_type)
{
    struct flock lock;
    lock.l_type = lock_type;
    lock.l_whence = SEEK_SET;   // Starting from the begining of the file
    lock.l_start = 0;  // no offset
    lock.l_len = 0;  // to the end of file. 0 means EOF
    if(flag == ACQUIRE_LOCK)
    {
        if(fcntl(fileno(fd), F_SETLKW, &lock) < 0)
        {
            perror("Error to acquire lock");
            return -1;
        }

    }  
   else
   {
       if(fcntl(fileno(fd), F_UNLCK, &lock) < 0)
       {
           perror("Error releasing lock");
           return -1;
       }

   }
   return 0;
}

What I expected : When A will release the lock, the content of the file should become
show table status
show action status

and when B will release the lock, the content of the file should become show action status and when C will release the lock, the file will become empty.

But

What I got: When A has released the lock, content of the file is same. All three lines are present. But When B has released the lock , I saw B has deleted the content show table status from the file and same C also deleted the show action status

This is not fixed behaviour, sometimes B does not delete the content but A deletes or C deletes.

I have got struck at this point. Looks to me that file is not getting sync between processes. Any help will be appreciated. Thanks in Advance!

vivek
  • 467
  • 2
  • 6
  • 18
  • Please take some time to read [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Some programmer dude Apr 13 '18 at 15:09
  • 1
    Are you aware that the opening brace in `if ((ret = strcmp (command, buf)) != 0) {` is not matched? – Arndt Jonasson Apr 13 '18 at 19:50
  • How do you call programs A, B and C so that they actually try to get the lock at the same time? – Arndt Jonasson Apr 13 '18 at 20:00
  • Maybe you should do a `fflush(fp)` before releasing the lock. – Arndt Jonasson Apr 13 '18 at 20:03
  • @ArndtJonasson Thank you for the response. Just wondering why u have suggested fflush. Any reason ? – vivek Apr 14 '18 at 05:16
  • Because output is buffered, and you want to make sure that all goes out to disk before the lock is released and the next process can do things to the file. The closing also flushes, but you have of course released the lock before the file is closed. – Arndt Jonasson Apr 14 '18 at 09:27
  • @ArndtJonasson, Here I am confuesed. As you said that `I have released the lock before file is closed`. I think this is the thumb rule, first release the lock and then close the file... – vivek Apr 15 '18 at 05:26
  • Another idea: perhaps you can refrain from releasing the lock explicitly, since closing the file ought to do release it too, but I am not completely certain about that. – Arndt Jonasson Apr 15 '18 at 15:28

0 Answers0