How do I lock files using fopen()?
I wonder if there is any way to lock and unlock a file in Linux when I open a file using fopen
(not open
)?
Based on Stack Overflow开发者_JS百科 question C fopen vs open, fopen
is preferred over open
.
How can I implement my own file lock (if possible) by creating and deleting lock files?
I would strongly disagree with the claim that fopen
is prefered over open
. It's impossible to use fopen
safely when writing a file in a directory that's writable by other users due to symlink vulnerabilities/race conditions, since there is no O_EXCL
option. If you need to use stdio on POSIX systems, it's best to use open
and fdopen
rather than calling fopen
directly.
Now, as for locking it depends on what you want to do. POSIX does not have mandatory locking like Windows, but if you just want to ensure you're working with a new file and not clobbering an existing file or following a symlink, use the O_EXCL
and O_NOFOLLOW
options, as appropriate. If you want to do cooperative locking beyond the initial open, use fcntl
locks.
In Linux, if you need a file descriptor (e.g., to pass to a file-locking primitive), you can use fileno(FILE*)
to retrieve it. After retrieving the file descriptor, you can use it as if it had been returned by open
.
For example, instead of
int fd = open("myfile.txt", flags);
int result = flock(fd, LOCK_SH);
you could equally well do this:
FILE* f = fopen("myfile.txt", "r");
int result = flock(fileno(f)), LOCK_SH);
Note that fileno
is defined in the POSIX standard, but not in C or C++ standards.
As for your second question, the Linux open()
man page has this to say:
The solution for performing atomic file locking using a lockfile is to create a unique file on the same file system (e.g., incorporating hostname and pid), use link(2) to make a link to the lockfile. If link() returns 0, the lock is successful. Otherwise, use stat(2) on the unique file to check if its link count has increased to 2, in which case the lock is also successful.
Files can be locked by using flock()
. Its syntax is
#include <sys/file.h>
#define LOCK_SH 1 /* shared lock */
#define LOCK_EX 2 /* exclusive lock */
#define LOCK_NB 4 /* don't block when locking */
#define LOCK_UN 8 /* unlock */
int flock(int fd, int operation);
First file is opened using fopen()
or open()
. Then this opened file is locked using flock()
as given below
int fd = open("test.txt","r");
int lock = flock(fd, LOCK_SH); // Lock the file . . .
// . . . .
// Locked file in use
// . . . .
int release = flock(fd, LOCK_UN); // Unlock the file . . .
Note that in below code fopen
will fail (and return NULL) if the lock file /var/lock/my.lock
doesn't exist.
FILE* f = fopen("/var/lock/my.lock", "r");
int result = flock(fileno(f)), LOCK_SH);
Use fopen
with w+
if you need the lockfile to be created if it doesn't exist.
FILE* f = fopen("/var/lock/my.lock", "w+");
int result = flock(fileno(f)), LOCK_SH);
If you wish to implement your own lock simply, I suggest Rob's answer of using flock. If you wish to implement it in a complex manner, such as for high availability, you can try something like using a thread to touch a file at a regular interval. All other programs wanting to lock the file should also check the file to see if its update time has been updated in at another fixed, but larger interval (the larger part is important). This is probably overkill for most applications, but it handles things such as crashes, freezes, etc. much better than flock.
There is another way with open() function, but I'm not sure about this called locked file. I am using file permissions to open a file.
The code is here:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#define FILE_NAME "hello.txt"
int main()
{
int fd;
fd = open(FILE_NAME, O_CREAT, S_IRWXU);
// Error checking
if(fd == -1){
perror("[error]\n");
}
else{
printf("[file is opened]\n");
}
return 0;
}
I used a flag for permissions (third argument). This flag gives read, write and execute permissions to the user.
$ls -alh
total 24K
drwxrwxr-x 2 arien arien 4.0K Dec 28 20:56 .
drwxrwxr-x 18 arien arien 4.0K Dec 27 22:20 ..
-rwxrwxr-x 1 arien arien 8.5K Dec 28 20:56 fopen
-rw-rw-r-- 1 arien arien 290 Dec 28 20:56 fopen.c
-rwx------ 1 arien arien 0 Dec 28 20:55 hello.txt
A little tip: If you are using Ubuntu or Debian, you can see the description of functions with man [function_name]
man pages of open() function.
The below code is not letting me lock the file using lockf, flock works fine though
#include <iostream>
#include <unistd.h>
#include<thread>
#include <vector>
#include <sys/file.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
void append()
{
FILE *fp=fopen("a.txt","a");
if(fp)
{
cout<<lockf(fileno(fp),F_LOCK,0)<<endl;
//flock(fileno(fp), LOCK_EX);
fprintf(fp,"abcdefghijklmnopqrstuvwxyz\n");fflush(fp);
sleep(1);
fprintf(fp,"^$^&%&*&^&*(*)_*)_()_*&***&(\n");fflush(fp);
fclose(fp);
}
else {
printf("null\n");
}
}
int main()
{
fclose(fopen("a.txt","w"));
//return 0;
vector<thread*> v;
//#pragma omp parallel for
for(int i=0;i<1000;++i)
{
v.push_back(new thread(append));
//append();
}
for(auto y:v)
{
y->join();
delete y;
}
return 0;
}
精彩评论