From 0e96092516cd490e3ab30e06f44ac82a8ae045e2 Mon Sep 17 00:00:00 2001 From: zhengshuxin Date: Wed, 24 Apr 2024 11:35:03 +0800 Subject: [PATCH] Try to use flock first to avoid the bugs in fcntl. --- lib_acl/src/stdlib/acl_myflock.c | 7 +- lib_acl_cpp/src/stream/fstream.cpp | 30 +++-- lib_fiber/samples/file_lock/Makefile | 3 + lib_fiber/samples/file_lock/main.cpp | 147 +++++++++++++++++++++++++ lib_fiber/samples/file_lock/stdafx.cpp | 8 ++ lib_fiber/samples/file_lock/stdafx.h | 20 ++++ 6 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 lib_fiber/samples/file_lock/Makefile create mode 100644 lib_fiber/samples/file_lock/main.cpp create mode 100644 lib_fiber/samples/file_lock/stdafx.cpp create mode 100644 lib_fiber/samples/file_lock/stdafx.h diff --git a/lib_acl/src/stdlib/acl_myflock.c b/lib_acl/src/stdlib/acl_myflock.c index eb547dc99..48a692b03 100644 --- a/lib_acl/src/stdlib/acl_myflock.c +++ b/lib_acl/src/stdlib/acl_myflock.c @@ -63,8 +63,7 @@ int acl_myflock(ACL_FILE_HANDLE fd, int lock_style, int operation) #endif /* - * fcntl() is standard and does more than we need, but we can handle - * it. + * fcntl() is standard and does more than we need, but we can handle it. */ #ifdef ACL_HAS_FCNTL_LOCK case ACL_FLOCK_STYLE_FCNTL: @@ -105,7 +104,7 @@ int acl_myflock(ACL_FILE_HANDLE fd, int lock_style, int operation) acl_set_error(ACL_EAGAIN); } - return (status); + return status; } #endif /* ACL_UNIX */ @@ -152,7 +151,7 @@ int acl_myflock(ACL_FILE_HANDLE fd, int lock_style acl_unused, int operation) } acl_msg_error("%s(%d): invalid lock_op(%d)", myname, __LINE__, lock_op); - return (-1); + return -1; } # else /* use LockFileEx/UnlockFileEx */ diff --git a/lib_acl_cpp/src/stream/fstream.cpp b/lib_acl_cpp/src/stream/fstream.cpp index fad6c2974..699d1bb53 100644 --- a/lib_acl_cpp/src/stream/fstream.cpp +++ b/lib_acl_cpp/src/stream/fstream.cpp @@ -215,9 +215,14 @@ bool fstream::lock(bool exclude /* = true */) return false; } - int ret = acl_myflock(fd, ACL_FLOCK_STYLE_FCNTL, - exclude ? ACL_FLOCK_OP_EXCLUSIVE : ACL_FLOCK_OP_SHARED); - return ret == 0; +#ifdef ACL_HAS_FLOCK_LOCK + // Use flock mode first when flock is supported by OS. + return acl_myflock(fd, ACL_FLOCK_STYLE_FLOCK, + exclude ? LOCK_EX : LOCK_SH) == 0; +#else + return acl_myflock(fd, ACL_FLOCK_STYLE_FCNTL, + exclude ? ACL_FLOCK_OP_EXCLUSIVE : ACL_FLOCK_OP_SHARED) == 0; +#endif } bool fstream::try_lock(bool exclude /* = true */) @@ -231,13 +236,14 @@ bool fstream::try_lock(bool exclude /* = true */) return false; } - int oper =ACL_FLOCK_OP_NOWAIT; - if (exclude) { - oper |= ACL_FLOCK_OP_EXCLUSIVE; - } else { - oper |= ACL_FLOCK_OP_SHARED; - } - return acl_myflock(fd, ACL_FLOCK_STYLE_FCNTL, oper) == 0; +#ifdef ACL_HAS_FLOCK_LOCK + return acl_myflock(fd, ACL_FLOCK_STYLE_FLOCK, + exclude ? (LOCK_EX | LOCK_NB) : (LOCK_SH | LOCK_NB)) == 0; +#else + return acl_myflock(fd, ACL_FLOCK_STYLE_FCNTL, + exclude ? (ACL_FLOCK_OP_NOWAIT | ACL_FLOCK_OP_EXCLUSIVE) + : (ACL_FLOCK_OP_NOWAIT | ACL_FLOCK_OP_SHARED)) == 0; +#endif } bool fstream::unlock(void) @@ -251,7 +257,11 @@ bool fstream::unlock(void) return false; } +#ifdef ACL_HAS_FLOCK_LOCK + return acl_myflock(fd, ACL_FLOCK_STYLE_FLOCK, ACL_FLOCK_OP_NONE) == 0; +#else return acl_myflock(fd, ACL_FLOCK_STYLE_FCNTL, ACL_FLOCK_OP_NONE) == 0; +#endif } } // namespace acl diff --git a/lib_fiber/samples/file_lock/Makefile b/lib_fiber/samples/file_lock/Makefile new file mode 100644 index 000000000..cd6f86035 --- /dev/null +++ b/lib_fiber/samples/file_lock/Makefile @@ -0,0 +1,3 @@ +include ../Makefile_cpp.in +CFLAGS += -DUSE_FIBER +PROG = file_lock diff --git a/lib_fiber/samples/file_lock/main.cpp b/lib_fiber/samples/file_lock/main.cpp new file mode 100644 index 000000000..dead5f828 --- /dev/null +++ b/lib_fiber/samples/file_lock/main.cpp @@ -0,0 +1,147 @@ +#include "stdafx.h" +#include +#include + +class locker { +public: + locker(const char* filepath, bool close_reader, int sleep_s) + : filepath_(filepath), close_reader_(close_reader), sleep_s_(sleep_s) {} + ~locker() {} + + void run() { + if (!fp_.open(filepath_, O_RDWR | O_CREAT, 0600)) { + printf("open %s error\r\n", filepath_.c_str()); + return; + } + + if (!fp_.try_lock()) { + printf("lock %s error %s\r\n", filepath_.c_str(), acl::last_serror()); + return; + } + + printf("lock %s ok\r\n", filepath_.c_str()); + + acl::ifstream reader; + if (reader.open_read(filepath_)) { + printf("open_read %s ok\r\n", filepath_.c_str()); + } else { + printf("open_read %s error\r\n", filepath_.c_str()); + } + + if (close_reader_) { + reader.close(); + } + + ::sleep(sleep_s_); + + if (!fp_.unlock()) { + printf("Unlock %s error %s\r\n", filepath_.c_str(), acl::last_serror()); + } else { + printf("Unlock %s ok\r\n", filepath_.c_str()); + } + + ::sleep(sleep_s_); + } + +private: + acl::string filepath_; + bool close_reader_; + int sleep_s_; + + acl::fstream fp_; +}; + +#ifdef USE_FIBER +class fiber_locker : public acl::fiber { +public: + fiber_locker(const char* filepath, bool close_reader, int sleep_s) + : filepath_(filepath), close_reader_(close_reader), sleep_s_(sleep_s) {} + ~fiber_locker() {} + +protected: + // @override + void run() { + printf("Running in fiber mode\r\n"); + locker lk(filepath_, close_reader_, sleep_s_); + lk.run(); + } + +private: + acl::string filepath_; + bool close_reader_; + int sleep_s_; +}; +#endif + +class thread_locker : public acl::thread { +public: + thread_locker(const char* filepath, bool close_reader, int sleep_s) + : filepath_(filepath), close_reader_(close_reader), sleep_s_(sleep_s) {} + ~thread_locker() {} + +protected: + // @override + void* run() { + printf("Running in thread mode\r\n"); + locker lk(filepath_, close_reader_, sleep_s_); + lk.run(); + return NULL; + } + +private: + acl::string filepath_; + bool close_reader_; + int sleep_s_; +}; + +static void usage(const char* procname) { + printf("usage: %s -h [help]\r\n" + " -t [if using thread mode, default: false]\r\n" + " -c [if closing reader, default: false]\r\n" + " -w sleep_time[default: 5]\r\n", procname); +} + +int main(int argc, char* argv[]) { + int ch, sleep_s = 5; + bool use_thread = false, close_reader = false; + + while ((ch = getopt(argc, argv, "htcw:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return 0; + case 't': + use_thread = true; + break; + case 'c': + close_reader = true; + break; + case 'w': + sleep_s = atoi(optarg); + if (sleep_s <= 0) { + sleep_s = 5; + } + break; + default: + break; + } + } + + acl::acl_cpp_init(); + acl::log::stdout_open(true); + + if (use_thread) { + thread_locker lk("./dummy.lock", close_reader, sleep_s); + lk.start(); + lk.wait(); + } else { +#ifdef USE_FIBER + acl::fiber::stdout_open(true); + fiber_locker lk("./dummy.lock", close_reader, sleep_s); + lk.start(); + acl::fiber::schedule(); +#endif + } + + return 0; +} diff --git a/lib_fiber/samples/file_lock/stdafx.cpp b/lib_fiber/samples/file_lock/stdafx.cpp new file mode 100644 index 000000000..f01a2ff42 --- /dev/null +++ b/lib_fiber/samples/file_lock/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_fiber/samples/file_lock/stdafx.h b/lib_fiber/samples/file_lock/stdafx.h new file mode 100644 index 000000000..194e37030 --- /dev/null +++ b/lib_fiber/samples/file_lock/stdafx.h @@ -0,0 +1,20 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "fiber/libfiber.hpp" +#include "acl_cpp/lib_acl.hpp" + +#ifdef WIN32 +#define snprintf _snprintf +#endif +