Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

File Locking

Status
Not open for further replies.

huskers

Programmer
Jan 29, 2002
75
US
Hi,

I have three instances of the same program running and writing to one file, I need to implemet file locking, can anyone please explain to me of how to implement this for the above scenario.

Thanks
Chak

 
Hi,

I open the file using append mode.
FILE *fp;

if (fp = fopen ("test.out", "+a") == NULL)
{
printf("File open errror\n");
}

I have three instances of program (say abc) running. Lets assume the instances to be a1, a2, a3. Now each instance will try to write to test.out so how can I make sure that only one writes to the file and the other wait until the lock is released in order to prevent data from corruption.

Any help would be appreciated.

Thanks
 
Huskers:

File locking is not an easy topic, and probably is not platform specific. Unix has a lockf function which locks and unlocks a file opened at low level. I'm giving you a test file, slock, I've been playing with.

I'm testing this under Unix Solaris 7. Execute slock which creates and locks the file if it isn't already existing, and sits there waiting for input. This locks the file until the user presses <CR> which unlocks at deletes the file.

In another unix instance, try executing slock and verify you can't do it until pressing <CR> in the slock program which originally locked the file.

What little I know about file locking I learned from W. Richard Stevens book &quot;Unix Network Programming&quot; ISBN 0-13-949876-1.

Regards,

Ed
Schaefer


/* slock - test file locking */
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

int execute_single_command(char *cmdstr, char *fflag);

char in_buf[BUFSIZ];
char exe_buf[BUFSIZ];

void main(int argc, char*argv[])
{
char *strptr = &quot;/tmp/lockfile.eds&quot;;
char x;
int ret_val, fd, lvalue;

while((fd = open(strptr, O_RDWR)) == -1)
{
printf(&quot;%s: file DOES NOT exist. create it\n&quot;, strptr);
strcpy(exe_buf, &quot;touch &quot;);
strcat(exe_buf, strptr);
strcat(exe_buf, &quot;;echo $?&quot;);
ret_val = execute_single_command(exe_buf, &quot;r&quot;);
}

printf(&quot;%s: file exists\n&quot;, strptr);
lvalue = lock_the_file(fd);
if(lvalue == 0)
printf(&quot;I'm locking the file: %d\n&quot;, lvalue);
else
{
printf(&quot;%s: file locked and I'm quitting\n&quot;, strptr);
exit(1);
}

printf(&quot;press return to continue to lift lock\n&quot;);
x=getchar();
close(fd);
unlock_the_file(fd);
unlink(strptr);
exit(1);

}

/*
* execute a single unix command as a pipe
*/
int execute_single_command(char *cmdstr, char *fmode)
{
FILE *pipe_in;
int cnt, xret;

if((pipe_in = popen(cmdstr, fmode)) == NULL)
{
fprintf(stderr, &quot;popen failed\n&quot;);
exit(1);
}
cnt = fread(in_buf, 1, BUFSIZ, pipe_in);
if(cnt)
{
if(in_buf[cnt-1] == '\n')
in_buf[cnt-1] = '\0';
}

xret = atoi(in_buf);

pclose(pipe_in);

return xret;
}

/*
* non blocking
*/
int lock_the_file(int fd)
{

int lock_val;

lseek(fd, 0L, 0L);
lock_val = lockf(fd, F_TLOCK, 0);

return lock_val;
}

/*
* unlock the file
*/
int unlock_the_file(int fd)
{

int lock_val;

lseek(fd, 0L, 0L);
lock_val = lockf(fd, F_ULOCK, 0);

}
 
File locking is definitely platform specific.

For UNIX systems, see fcntl(). This function at least conforms to POSIX, so it should work across Unices.

For Win32, hmmm...LockFile() should do the trick.
Russ
bobbitts@hotmail.com
 
Russ:

You caught be in a freudian slip. Sorry, I meant to say it was platform specific. Hopefully, the code isn't slipping!

Ed
 
Question about File locking.

10 different instances access the same file some read only, some read and write. How do we avoid bottleneck?
 
why you not use ipcs or semaphores ??



#include <stdio.h>



#ifndef IpcMax

#define IpcMax 2048

#endif



#ifdef MAIN

int myusage(char *);

extern int ipc_lock(int,int,char *,char *);

#else

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/errno.h>

#include <time.h>

extern char *sys_errlist[];

extern int errno;

#endif



/* request for locking facility - ipc */



#define LOCKipc 'f'

#define KILLipc 'k'

#define ASKSipc 'q'

#define READipc 'r'

#define WRITipc 'w'

#define VERBipc 's'



/******** the code above should be in a xxxinclude/ipc_request.h file ******/



#include <xxxinclude/ipc_request.h>



#ifdef MAIN



int main(int argc, char **argv)

{

extern char *basename(char *);

char *myname = basename(*argv);



if(argc != 3) exit(myusage(myname));

++argv; argc = 0;

if(**argv != '-') exit(myusage(myname));



for(++*argv; **argv; ++*argv){

switch(**argv){

case VERBipc:

argc = 1; break;

case LOCKipc:

case KILLipc:

exit(myipc_lock(**argv,argc,*++argv,&quot;&quot;));

case ASKSipc:

case READipc:

exit(myipc_lock(**argv,-1,*++argv,&quot;&quot;));

default:

break;

}

}

exit(myusage(myname));

}



int myusage(char *name)

{

fprintf(stderr,&quot;\nUSAGE: %s -[%c]%c exec-name&quot;,name,VERBipc,ASKSipc);

fprintf(stderr,&quot;\n query ipc-lock status for exec-name&quot;);

fprintf(stderr,&quot;\nUSAGE: %s -[%c]%c exec-name&quot;,name,VERBipc,LOCKipc);

fprintf(stderr,&quot;\n force lock ipc for exec-name&quot;);

fprintf(stderr,&quot;\nUSAGE: %s -[%c]%c exec-name&quot;,name,VERBipc,KILLipc);

fprintf(stderr,&quot;\n unlock/remove ipc for exec-name&quot;);

fprintf(stderr,&quot;\n NOTA: use '%c' for silent-mode&quot;,VERBipc);

fprintf(stderr,&quot;\n to do this by hand, get the qid, enter: ipcs -q&quot;);

fprintf(stderr,&quot;\n then kill the ipc, enter: ipcrm -q <qid>&quot;);

return(1);

}



#else /* ifdef MAIN this comment is used, do not delete !!! */



int how2unlock(char *name, char *interpreter, char *exec, char *ipcid)

{

printf(&quot;\n\n\t*** ERROR ***\n&quot;);

printf(&quot;\n\t'%s' is a SINGLE-USER application !!!&quot;,name);

printf(&quot;\n\tit uses the 'ipcs'unix-feature for locking, to check this enter&quot;);

printf(&quot;\n\n\tipcs -q\n&quot;);

printf(&quot;\n\tyou will get on stdout, the 'ipcs'queue id = %s.&quot;,ipcid);

printf(&quot;\n\tPlease check if '%s' is running, to do this enter&quot;,name);

printf(&quot;\n\n\tps -ef|grep %s\n&quot;,exec);

printf(&quot;\n\t'%s' is RUNNING if you get a line like:&quot;,name);

printf(&quot;\n\t<any strings> %s <any strings> %s&quot;,interpreter,exec);

printf(&quot;\n\n\tThe reason of this message even if '%s' is NOT RUNNING:&quot;,name);

printf(&quot;\n\tthe last session of '%s' was killed by 'kill', so it got&quot;,name);

printf(&quot;\n\tno chances to cleanup his 'ipcs'lock, this is still in memory.&quot;);

printf(&quot;\n\tThe only way to unlock is to manually kill the 'ipcs' to do this enter&quot;);

printf(&quot;\n\n\tipcrm -q %s\n&quot;,ipcid);

printf(&quot;\n\tExiting...\n\n&quot;);

return(1);

}



int myipc_lock(int wie, int verb,char *name, char *was)

{

struct msqid_ds dummy;

struct { long type ; char mssg[IpcMax+1]; } ipc;

register int qid, len;

key_t mykey_que();



if(0 >(qid = msgget(mykey_que(name),IPC_CREAT|0666))){

if(verb) fprintf(stderr,&quot;myipc_lock[%d] ERROR %d %s\n&quot;,__LINE__,errno,sys_errlist[errno]);

return(-1);

}



ipc.type = 1L; memset(ipc.mssg,NULL,IpcMax);



len = 1+msgrcv(qid,(char *)&(ipc.type),IpcMax,ipc.type,IPC_NOWAIT);



switch(wie){

case LOCKipc:

strcpy(ipc.mssg,name); len = 1;

break;

case WRITipc:

strcpy(ipc.mssg,was); len = 1;

break;

case READipc:

if(0 >verb) printf(&quot;[ %d ] %s\n&quot;,qid,ipc.mssg);

else strcpy(was,ipc.mssg);

break;

case ASKSipc:

if(verb){

if(!len) printf(&quot;\n\t*** %s: UNLOCKED ***\n\n&quot;,name);

else{

printf(&quot;\n\t[ %d ] *** LOCKED by %s ***\n\n&quot;,qid,ipc.mssg);

break;

}

}

if(len){ sprintf(was,&quot;%d&quot;,qid); break; }

case KILLipc:

if(!msgctl(qid,IPC_RMID,&dummy)) return(0);

if(verb) fprintf(stderr,&quot;myipc_lock[%d] ERROR %d %s\n&quot;,__LINE__,errno,sys_errlist[errno]);

return(-1);

}



/*** write or restore message removed by 'msgrcv' ***/

if(len && msgsnd(qid,&ipc,strlen(ipc.mssg),0)){

if(verb) fprintf(stderr,&quot;myipc_lock[%d] ERROR %d %s\n&quot;,__LINE__,errno,sys_errlist[errno]);

return(-1);

}

return(len);

}



key_t mykey_que(register char *input)

{

key_t key = (key_t)0;

register int pos = 0;

while(sizeof(key_t) >pos && input[pos]) key = (key<< 8) | input[pos++];

return(key);

}

#endif



/******** the code above is your ipc-lock */





/******** here your main exec using the lock mechanisme above ***/



#define MYIPCNAME &quot;abcdefgh&quot;

#include <xxxinclude/ipc_request.h>



int main(int argc, char **argv)

{

extern int myipc_lock(int,int,char *,char *);

extern char *basename(char *);



char buff[MaxBuff+1];



myname = basename(*argv);



if(myipc_lock(ASKSipc,0,MYIPCNAME,buff))

exit(how2unlock(myname,&quot;/bin/sh&quot;,MYIPCNAME,buff));



if(myipc_lock(WRITEpc,0,MYIPCNAME,buff)) exit(1);



/*

your code

*/



exit(myipc_lock(KILLipc,0,MYIPCNAME,&quot;&quot;));

}

/***************************************



write it in (exemple) myipc_lock.c myexec.c

then link: ln -s myipc_lock.c .omyipc_lock.c

complile: (g)cc YourOptions -o .omyipc_lock.o .omyipc_lock.c

make libs: /usr/ccs/bin/ar rv libAAA.a .omyipc_lock.o

complile: (g)cc YourOptions -DMAIN -L. -o myipc_lock myipc_lock.c -llibAAA.a

complile: (g)cc YourOptions -DMAIN -L. -o myexec myexec.c -lAAA -llibAAA.a

********/

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top