文件锁

来源:互联网 发布:罪恶装备人物乐乎 编辑:程序博客网 时间:2024/05/21 09:58

利用mktemp和fcntl实现进程间互斥操作

struct flock lock_it, unlock_it;
int lock_fd = -1;

void my_lock_init(char *pathname)
{
char lock_file[64];

strncpy(lock_file, pathname, sizeof(lock_file));
lock_file[sizeof(lock_file) - 1] = '/0';

if (mktemp(lock_file) == NULL) {
perror("mktemp");
exit(-1);
}
if ((lock_fd = open(lock_file, O_CREAT | O_WRONLY, 0600)) < 0) {
perror("open lock file");
exit(-1);
}
unlink(lock_file); /* unlink 不影响文件打开状态,也省却了某些
* 好事者看见锁文件就妄图删除之为快 */


lock_it.l_type = F_WRLCK;
lock_it.l_whence = SEEK_SET;
lock_it.l_start = 0;
lock_it.l_len = 0;

unlock_it.l_type = F_UNLCK;
unlock_it.l_whence = SEEK_SET;
unlock_it.l_start = 0;
unlock_it.l_len = 0;
}

void my_lock( )
{
while (fcntl(lock_fd, F_SETLKW, &lock_it) < 0) {
if (errno == EINTR)
continue;
else {
perror("fcntl lock");
exit(-1);
}
}
}

void my_unlock( )
{
if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) {
perror("fcntl lock");
exit(-1);
}
}

文件描述符和文件流之间的转换

FILE *fdopen(int fildes, const char *type);

这个函数很有用的,功能是将一个流关联到一个打开的文件号filedes上,该filedes可以是open、pipe、dup、dup2和creat等调用返回的结果。type指定流打开方式,同fopen的打开方式,如"a","r","w"等等,fdopen的流打开方式服从filedes的打开方式,比如filedes的open指定O_RDONLY,那么fdopen也只能指定"r"的打开方式了。

用fdopen的好处很明显,如果你不得已只能打开文件号,比如socket或者dup调用,但又想用fprintf,fscanf等流操作来进行读写,那么就再fdopen一次好了。

int fileno(FILE stream);

用fileno有什么好处呢?你用fopen打开了文件,但是又想用flock或者lockf来给文件加锁,或者用fcntl来进行某些底层的操作,但上述这些函数只能对打开的文件号操作,而不能对打开流,这时候就用fileno再flock、lockf、fcntl好了。

如何避免产生zombie process

通常一个子进程终止后,需要父进程对其进行善后工作(获取子进程的结束状态,释放它仍占用的资源等等),wait系统调用就是干这件事。在子进程结束后,父进程还没有对它善后之前这段时间,这个子进程就是zombieprocess(僵死进程)。如果父进程无法wait子进程,怎样才能避免zombie呢?有两种办法:

  1. 捕获SIGCHLD信号。子进程正常或异常结束时,内核就会向其父进程发送SIGCHLD信号。所以我们可以这样设置这个信号的处理函数:
static void sigchld(int sig)
{
int rv;
do
rv = waitpid(0, NULL, WNOHANG);
while (rv > 0);
}
  1. 连续fork两次。子进程直接退出,孙子进程被init进程接管,所以就不用担心它会成为zombie了。

如何成为daemon进程

下面是从《Unix高级环境编程》摘过来的代码(Page 314):

static int daemon_init()
{
pid_t pid;

if((pid = fork()) <0)
return -1;
else if(pid !=0 )
exit(0); /* parent goes bye-bye */

/* child continues */

setsid(); /* become session leader */

chdir("/"); /* change working directory */

umask(0); /* clear our file mode creation mask */

return 0;
}

如何使一个程序同时只能运行一个进程实例

利用PID文件和文件锁实现。PID文件就是一个保存了进程pid的文件。

#define PIDFILE "/tmp/proc.pid"

static int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;

lock.l_type = type;
lock.l_start = offset;
lock.l_whence = whence;
lock.l_len = len;

return (fcntl(fd,cmd, &lock));
}

#define write_lock(fd, offset, whence, len) lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)

static void check_single_on()
{
int fd, val;
char buf[10];

if((fd = open(PIDFILE, O_WRONLY | O_CREAT, 0644)) <0 ) {
perror("open in check_single_on()");
exit(1);
}

/* try and set a write lock on the entire file */
if(write_lock(fd, 0, SEEK_SET, 0) <0 ) {
if(errno == EACCES || errno == EAGAIN) {
printf("daemon is already running./n");
exit(0); /* gracefully exit, daemon is already running */
}else {
perror("write_lock");
close(fd);
exit(1);
}
}

/* truncate to zero length, now that we have the lock */
if(ftruncate(fd, 0) <0) {
perror("ftruncate");
close(fd);
exit(1);
}

/* write our process id */
sprintf(buf, "%d/n", getpid());
if(write(fd, buf, strlen(buf)) != strlen(buf)) {
perror("write in check_single_on()");
close(fd);
exit(1);
}

/* set close-on-exec flag for descriptor */
if((val = fcntl(fd, F_GETFD, 0) <0 )) {
perror("fcntl");
close(fd);
exit(1);
}
val |= FD_CLOEXEC;
if(fcntl(fd, F_SETFD, val) <0 ) {
perror("fcntl again");
close(fd);
exit(1);
}

/* leave file open until we terminate: lock will be held */

}

检测一个进程是否正在运行:

static int check_proc_running()
{
int fd, rv;
char buf[10];

if((fd = open(PIDFILE, O_RDWR | O_CREAT, 0644)) <0 ) {
perror("open in check_proc_running()");
exit(1);
}

/* try and set a write lock on the entire file */
if(write_lock(fd, 0, SEEK_SET, 0) <0 ) {
if(errno == EACCES || errno == EAGAIN) {
bzero(buf, 10);
rv = read(fd, buf, 10);
buf[rv] = '/0';

close(fd);
return atoi(buf);
}else {
perror("write_lock");
close(fd);
return -1;
}
}

close(fd);

printf("daemon is not running now./n");

return -1;
}