In Linux, there are two types of File Locking: one is to create a lock file through atomic operations, and the other is to allow access to this part of the content to be locked.
1. Lock files
Many applications only need to be able to create a lock file for a resource, and other programs can check the file to determine whether they are allowed to access the resource. Create a lock file and use the fcntl. h header file (located under/usr/include on the host) to call the open system, with the o_creat and o_excl labels. In this way, two tasks are completed in an atomic operation: Determine whether the file does not exist, and then create
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <errno.h>int main(){ int file_desc; int save_errno; file_desc = open("/tmp/LCK.test", O_RDWR | O_CREAT | O_EXCL, 0444); if (file_desc == -1) { save_errno = errno; printf("Open failed with error %d\n", save_errno); } else { printf("Open succeeded\n"); } exit(EXIT_SUCCESS);}
However, when you run the above program for the second time, an error will be prompted: Open failed with error 17 (the file already exists, the error code is in/usr/include/ASM-generic/error-base.h ), if you want the program to run successfully again, you must delete the lock file. In C language calls, we can use the unlink function (defined in/usr/include/unistd. h ). In addition, the above Code is not very reasonable, only open is not close, under normal circumstances, you should add the following two lines:
(void)close(file_desc); (void)unlink( "/tmp/LCK.test");
For details about unlink, refer to the http://bbs.chinaunix.net/thread-1920145-1-1.html statement. The unlink prototype is as follows:
#include <unistd.h>int unlink (__const char *__name)
Function: delete a directory item and link the file referenced by _ nameCountMinus 1. When the link count is 0, the file is deleted.
For how to use unlink, refer to Chapter 17th of "Advanced Programming for Unix environment", which is a unique link of 17.3.2. Before listen, unlink should be used to prevent the file from already exists, accept should be used before Unlink, prevents problems in the next call. Once the landlord encountered address in use on ACE's Unix domain socket ace_lsock, which is actually because the lock file has not been deleted.
2. region lock
A region lock occurs because the file locking method is not suitable for accessing large shared files. If a large file is written into data by a program, different programs update the file at the same time. The handler cannot wait until the record program ends. Therefore, some coordination methods are required to provide concurrent access to the same file. Linux provides two methods for implementation: fcntl System Call and lockf call.
An example of locking a file using fcntl is as follows:
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>const char *test_file = "/tmp/test_lock";int main() { int file_desc; int byte_count; char *byte_to_write = "A"; struct flock region_1; struct flock region_2; int res; /* open a file descriptor */ file_desc = open(test_file, O_RDWR | O_CREAT, 0666); if (!file_desc) { fprintf(stderr, "Unable to open %s for read/write\n", test_file); exit(EXIT_FAILURE); } /* put some data in the file */ for(byte_count = 0; byte_count < 100; byte_count++) { (void)write(file_desc, byte_to_write, 1); } /* setup region 1, a shared lock, from bytes 10 -> 30 */ region_1.l_type = F_RDLCK; region_1.l_whence = SEEK_SET; region_1.l_start = 10; region_1.l_len = 20; /* setup region 2, an exclusive lock, from bytes 40 -> 50 */ region_2.l_type = F_WRLCK; region_2.l_whence = SEEK_SET; region_2.l_start = 40; region_2.l_len = 10; /* now lock the file */ printf("Process %d locking file\n", getpid()); res = fcntl(file_desc, F_SETLK, ion_1); if (res == -1) fprintf(stderr, "Failed to lock region 1\n"); res = fcntl(file_desc, F_SETLK, ion_2); if (res == -1) fprintf(stderr, "Failed to lock region 2\n"); /* and wait for a while */ sleep(60); printf("Process %d closing file\n", getpid()); close(file_desc); exit(EXIT_SUCCESS);}
The program first creates a file, then opens it in read/write mode, and adds some data. Then, set two areas in the file. The first one is 0-30, and the lock is read (shared). The second one is 40-50, and the lock is written (exclusive, then, call fcntl to lock the two regions.
The fcntl parameter provides three Command Options
F_getlk, f_setlk, and f_setlkw. The options provided by l_type include f_rdlck, f_unlck, and f_wrlck, which are read, unlock, and write locks respectively.
The lock test procedure is as follows:
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>const char *test_file = "/tmp/test_lock";#define SIZE_TO_TRY 5void show_lock_info(struct flock *to_show);int main() { int file_desc; int res; struct flock region_to_test; int start_byte; /* open a file descriptor */ file_desc = open(test_file, O_RDWR | O_CREAT, 0666); if (!file_desc) { fprintf(stderr, "Unable to open %s for read/write", test_file); exit(EXIT_FAILURE); } for (start_byte = 0; start_byte < 99; start_byte += SIZE_TO_TRY) { /* set up the region we wish to test */ region_to_test.l_type = F_WRLCK; region_to_test.l_whence = SEEK_SET; region_to_test.l_start = start_byte; region_to_test.l_len = SIZE_TO_TRY; region_to_test.l_pid = -1; printf("Testing F_WRLCK on region from %d to %d\n", start_byte, start_byte + SIZE_TO_TRY); /* now test the lock on the file */ res = fcntl(file_desc, F_GETLK, ion_to_test); if (res == -1) { fprintf(stderr, "F_GETLK failed\n"); exit(EXIT_FAILURE); } if (region_to_test.l_pid != -1) { printf("Lock would fail. F_GETLK returned:\n"); show_lock_info(ion_to_test); } else { printf("F_WRLCK - Lock would succeed\n"); } /* now repeat the test with a shared (read) lock */ /* set up the region we wish to test */ region_to_test.l_type = F_RDLCK; region_to_test.l_whence = SEEK_SET; region_to_test.l_start = start_byte; region_to_test.l_len = SIZE_TO_TRY; region_to_test.l_pid = -1; printf("Testing F_RDLCK on region from %d to %d\n", start_byte, start_byte + SIZE_TO_TRY); /* now test the lock on the file */ res = fcntl(file_desc, F_GETLK, ion_to_test); if (res == -1) { fprintf(stderr, "F_GETLK failed\n"); exit(EXIT_FAILURE); } if (region_to_test.l_pid != -1) { printf("Lock would fail. F_GETLK returned:\n"); show_lock_info(ion_to_test); } else { printf("F_RDLCK - Lock would succeed\n"); } } /* for */ close(file_desc); exit(EXIT_SUCCESS);}void show_lock_info(struct flock *to_show) { printf("\tl_type %d, ", to_show->l_type); printf("l_whence %d, ", to_show->l_whence); printf("l_start %d, ", (int)to_show->l_start); printf("l_len %d, ", (int)to_show->l_len); printf("l_pid %d\n", to_show->l_pid);}
(Most of the above content comes from Linux programming)
That's it. More and more things are encountered.