Flock 函数 互斥锁 线程可用, 多进程可用,但fork进程不行
Fcntl 函数 多进程可用 fork进程可用 但线程不行
Fcntl函数的记录锁所用来设置对文件进行加密,所以无论是fork还是多个程序对同一个文件均可以起到加锁的作用。但对线程则没有作用。简单使用可以,涉及到多进程特别是fork的话就需要注意了。因为fork继承此文件描述符,在fork中释放锁,那么也就是主进程释放锁了。
Flock函数只能用来对整个文件加锁,多个线程对同一个文件也可以,但是fork的进程不行。
所以总的来说对进程加锁采用fcntl,需要线程安全的话就还是选择线程锁,比如互斥锁,或者读写锁(这个是共享互斥锁)等。
下面是我的测试代码。Wrapfcntl这两个文件是对fcntl函数的包装,采用<unix环境高级编程>数中的例子。这本书里的代码很经典的,不但了解函数的使用,还介绍了环境,使用注意等。比百度到的要了解的透彻多了,就像我这里写的,只是个笔记或者总结而已。
******************************** wrapfcntl.h *********************************
#ifndef IRIDIUMFCNTL_H
#define IRIDIUMFCNTL_H
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* about files */
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
/* fcntl函数的包装,带w表示阻塞调用*/
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len);
#endif
******************************** wrapfcntl.c *********************************
#include "wrapfcntl.h"
int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
lock.l_start = offset; /* byte offset, relative to l_whence */
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
lock.l_len = len; /* #bytes (0 means to EOF) */
return (fcntl(fd, cmd, &lock));
}
******************************** main.c *********************************
/*gcc main.c wrapfcntl.c 测试多进程的fcntl锁 */
/*gcc main.c wrapfcntl.c -DTEST_FLOCK 测试多进程的flock锁 */
/*gcc main.c wrapfcntl.c -DTEST_PTHREAD -lpthread 测试多线程的fcntl锁 */
/*gcc main.c wrapfcntl.c -DTEST_FLOCK -lpthread 测试多线程的flock锁 */
#include "wrapfcntl.h"
#define THREAD_NUM 1
void *thread_function(void *arg);
const char main_process[] = "++++++++++ this is the main process \n";
const char child_process[] = "---------- this is the child process \n";
const char pthread[] = "======== this is the child thread \n";
//#define TEST_FLOCK
int fd;
const sleep_s = 10;
int main()
{
int res;
pthread_t thread_group[THREAD_NUM];
void *(*thread_func_group[THREAD_NUM])(void *);
int i;
char info[THREAD_NUM][20];
char temp[20];
for(i = 0; i< THREAD_NUM; i++){
sprintf(temp, "%d%d%d%d%d", i, i, i, i, i);
strcpy(info[i], temp);
}
for( i = 0; i < THREAD_NUM; i++)
thread_func_group[i] = thread_function;
void *thread_result;
int n = 0;
fd = open("/var/log/iridium/test.log", O_CREAT|O_APPEND|O_RDWR, 0744);
if(fd < 0){
printf("open error fd = %d\n", fd);
return -1;
}
#ifdef TEST_PTHREAD
printf("Testing pthread =========================\n");
#elif defined TEST_FLOCK
printf("Testing flock ==========================\n");
#else
printf("Testing multi process ==================\n");
#endif
#ifdef TEST_PTHREAD
for(i = 0 ; i < THREAD_NUM; i++){
res = pthread_create(&(thread_group[i]), NULL, thread_func_group[i], (void*)(info[i]));
if (res != 0)
{
perror("Thread creation failed!");
return -1;
}
}
#else
if(fork() == 0){
while(1){
printf("child process waiting lock\n");
#ifdef TEST_FLOCK
flock(fd, LOCK_EX);
#else
writew_lock(fd, 0, SEEK_SET, 0);
#endif
n = write(fd, child_process, strlen(child_process));
if(n < 0)
printf("-----------child write error\n");
fprintf(stderr, "%s ********** after %d s unlock\n", child_process, sleep_s);
sleep(sleep_s);
#ifdef TEST_FLOCK
flock(fd, LOCK_UN);
#else
un_lock(fd, 0 ,SEEK_SET, 0);
#endif
usleep(1);
}
}
#endif
while(1){
printf("main\n");
#ifdef TEST_FLOCK
flock(fd, LOCK_EX);
#else
writew_lock(fd, 0, SEEK_SET, 0);
#endif
n = write(fd, main_process, strlen(main_process));
if(n < 0)
printf("++++++++++++++main write error\n");
fprintf(stderr, "%s ********** after %d s unlock\n", main_process, sleep_s);
sleep(sleep_s);
#ifdef TEST_FLOCK
flock(fd, LOCK_UN);
#else
un_lock(fd, 0, SEEK_SET, 0);
usleep(1);
#endif
}
/* 忽略多个线程同时终止的问题,代码不会执行到此,线程随进程终止 */
for(i = 0; i < THREAD_NUM; i++){
pthread_join(thread_group[i], NULL);
}
close(fd);
return 0;
}
void *thread_function(void *arg)
{
#if 1
int n = 0;
while(1){
#ifdef TEST_FLOCK
flock(fd, LOCK_EX);
#else
writew_lock(fd, 0, SEEK_SET, 0);
#endif
n = write(fd, pthread, strlen(pthread));
if(n < 0)
printf("=================child write error\n");
fprintf(stderr, "%s ********** after %d s unlock\n", pthread, sleep_s);
sleep(sleep_s);
#ifdef TEST_FLOCK
flock(fd, LOCK_UN);
#else
un_lock(fd, 0 ,SEEK_SET, 0);
#endif
}
close(fd);
#endif
return ;
}