linux -用flock实现单进程启动

前言

在TLPI上看到,用flock可以检测建议锁。可以用来检测单进程启动。写个demo整理一下。

运行效果

Jan  1 19:08:12 debian9 test_file_locker: [MY_LOGD : main.cpp.31 : main()] : ok, lock /var/lock/my_prog/my_prog_was_exist, i was the first process

Jan  1 19:08:21 debian9 test_file_locker: [MY_LOGD : ../../component/file_locker/file_locker.cpp.73 : lock_file()] : flock failed : Resource temporarily unavailable
Jan  1 19:08:21 debian9 test_file_locker: [MY_LOGD : main.cpp.27 : main()] : can't lock /var/lock/my_prog/my_prog_was_exist, maybe i wasn't first process
Jan  1 19:08:21 debian9 test_file_locker: [MY_LOGD : main.cpp.39 : main()] : bye

demo下载点

src_test_file_locker.7z

实验

// @file main.cpp
// @brief 测试后来的进程是否能打开文件锁, 如果打不开就对了
// @note 
// 	实验环境:
//	debian9.6

#include <stdlib.h> // for EXIT_SUCCESS
#include <stdio.h> // for snprintf

#include "const_define.h" // for FILE_VAR_LOCK
#include "sys_log.h" // for MYLOG_D
#include "file_locker.h" // for cls_file_locker

int main(int argc, char** argv)
{
	int i_rc = EXIT_FAILURE;
	cls_file_locker locker;
	char sz_buf[0x1000] = {'\0'};

	do {
		snprintf(sz_buf, sizeof(sz_buf), "mkdir -p %s", DIR_VAR_LOCK);
		system(sz_buf);

		if (!locker.lock_file(FILE_VAR_LOCK)) {
			MYLOG_D("can't lock %s, maybe i wasn't first process", FILE_VAR_LOCK);
			break;
		}

		MYLOG_D("ok, lock %s, i was the first process", FILE_VAR_LOCK);

		printf("runing..., press any key to quit");
		getchar();
		
		i_rc = EXIT_SUCCESS;
	} while (0);

	MYLOG_D("bye");
	
	return i_rc;
}


// @file linux_prj\component\file_locker\file_locker.h

#ifndef __LINUX_PRJ__COMPONENT__FILE_LOCKER__FILE_LOCKER_H__
#define __LINUX_PRJ__COMPONENT__FILE_LOCKER__FILE_LOCKER_H__

class cls_file_locker
{
public:
	cls_file_locker();
	virtual ~cls_file_locker();

	bool lock_file(const char* psz_file_path_name);

private:
	int m_i_fd;
	const int m_i_lock_type;
	bool m_b_lock_ok;
};

#endif // #ifndef __LINUX_PRJ__COMPONENT__FILE_LOCKER__FILE_LOCKER_H__

// @file linux_prj\component\file_locker\file_locker.cpp

// /usr/include/asm-generic/errno.h
// /usr/include/asm-generic/errno-base.h

#include <stdio.h> // for printf
#include <unistd.h> // for close
#include <sys/file.h> // for flock()
#include <fcntl.h> // for O_RDWR, struct flock
#include <errno.h> // for error
#include <string.h> // for strerror

#include "file_locker.h"
#include "sys_log.h"

// #define FILE_PERMS	(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
#define FILE_PERMS 0

cls_file_locker::cls_file_locker()
: m_i_fd(-1), m_i_lock_type(LOCK_EX | LOCK_NB), m_b_lock_ok(false)
{
	// m_i_lock_type 为互斥锁 + 非阻塞, 此文件锁只能有一个主人
}

cls_file_locker::~cls_file_locker()
{
	if (-1 != m_i_fd) {
		if (m_b_lock_ok) {
			flock(m_i_fd, LOCK_UN); // 解锁
		}
		
		close(m_i_fd);
		m_i_fd = -1;
	}
}

bool cls_file_locker::lock_file(const char* psz_file_path_name)
{
	bool b_rc = false;
	int i_rc = -1;
	
	do {
		if (NULL == psz_file_path_name) {
			break;
		}

		// O_EXCL 是独占
		// 第一次打开文件,假设文件不存在
		m_i_fd = open(psz_file_path_name, O_RDWR | O_CREAT | O_EXCL, FILE_PERMS);
		if (-1 == m_i_fd) {
			if (EEXIST != errno) {
				// 如果第一次打开,不是由于文件已经存在引起的打开错误,那就是真的错了
				MYLOG_D("open failed : %s", strerror(errno));
				break;
			}
			
			// 如果文件已经存在, 只用独占和读写去打开试试
			m_i_fd = open(psz_file_path_name, O_RDWR | O_EXCL, FILE_PERMS);
			if (-1 == m_i_fd) {
				MYLOG_D("open failed : %s", strerror(errno));
				break;
			}
		}

		// flock在NFS(分布式网络文件服务器)上无效
		// flock是建议锁, 要操作文件的程序必须要先上锁,得到锁后,再操作文件
		// 建议锁并没有将锁和文件关联在一起
		// 如果m_i_lock_type 不带 LOCK_NB 选项, 拿不到锁会阻塞
		// 如果m_i_lock_type 带 LOCK_NB 选项, 拿不到锁会返回错误码,这种场景用来检测单进程启动不错
		i_rc = flock(m_i_fd, m_i_lock_type); // 用共享方式打开文件锁
		m_b_lock_ok = (-1 != i_rc);
		if (-1 == i_rc) {
			MYLOG_D("flock failed : %s", strerror(errno));
			break;
		}

		b_rc = true;
	} while (0);
	
	return b_rc;
}


猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/85554407