- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
标准 Linux fcntl
调用不提供超时选项。我正在考虑用信号实现超时锁定。
这里是阻塞锁的描述:
F_SETLKW
此命令等同于 F_SETLK,除了如果共享锁或排他锁被其他锁阻塞,线程将等待直到请求得到满足。 如果在 fcntl() 等待区域时接收到要捕获的信号,fcntl() 将被中断。 从信号处理程序返回时,fcntl() 将返回 -1 和错误号设置为[EINTR],不进行锁操作。
那么我需要用什么样的信号来表示锁要被中断呢?而且由于我的进程中有多个线程在运行,我只想中断这个阻塞文件锁的IO线程,其他线程不应该受到影响,但是信号是进程级的,我不确定如何处理这种情况。
我已经使用信号编写了一个简单的实现。
int main(int argc, char **argv) {
std::string lock_path = "a.lck";
int fd = open(lock_path.c_str(), O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
if (argc > 1) {
signal(SIGALRM, [](int sig) {});
std::thread([](pthread_t tid, unsigned int seconds) {
sleep(seconds);
pthread_kill(tid, SIGALRM);
}, pthread_self(), 3).detach();
int ret = file_rwlock(fd, F_SETLKW, F_WRLCK);
if (ret == -1) std::cout << "FAIL to acquire lock after waiting 3s!" << std::endl;
} else {
file_rwlock(fd, F_SETLKW, F_WRLCK);
while (1);
}
return 0;
}
通过运行 ./main
然后是 ./main a
,我希望第一个进程永远持有锁,第二个进程尝试获取锁并在之后中断3s,但第二个进程刚刚终止。
有人能告诉我我的代码有什么问题吗?
最佳答案
So what kind of signal I need to use to indicate the lock to beinterrupted?
最明显的信号选择是 SIGUSR1
或 SIGUSR2
。提供这些是为了满足用户定义的目的。
还有 SIGALRM
,如果您使用产生此类信号的计时器来进行计时,这将是很自然的,并且即使以编程方式生成它也有意义,只要您不将其用于其他目的。
And since there're multiple threads running in myprocess, I only want to interrupt this IO thread who is blokcing forthe file lock, other threads should not be affected, but signal isprocess-level, I'm not sure how to handle this situation.
您可以通过 pthread_kill()
函数向多线程进程中的选定线程传递信号。这也适用于多个线程同时等待锁的情况。
使用常规 kill()
,您还可以选择让所有线程阻塞所选信号 (sigprocmask()
),然后让线程进行锁定尝试立即解锁它。 When the chosen signal is delivered to the process, a thread that is not presently blocking it will receive it, if any such thread is available.
这假设已经设置了一个信号处理程序来处理所选信号(它不需要做任何事情),并且可以通过符号 LOCK_TIMER_SIGNAL
获得要使用的信号编号.它提供了所需的超时行为作为围绕 fcntl()
的包装函数,使用问题中描述的命令 F_SETLKW
。
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/syscall.h>
#if (__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 30)
// glibc prior to 2.30 does not provide a wrapper
// function for this syscall:
static pid_t gettid(void) {
return syscall(SYS_gettid);
}
#endif
/**
* Attempt to acquire an fcntl() lock, with timeout
*
* fd: an open file descriptor identifying the file to lock
* lock_info: a pointer to a struct flock describing the wanted lock operation
* to_secs: a time_t representing the amount of time to wait before timing out
*/
int try_lock(int fd, struct flock *lock_info, time_t to_secs) {
int result;
timer_t timer;
result = timer_create(CLOCK_MONOTONIC,
& (struct sigevent) {
.sigev_notify = SIGEV_THREAD_ID,
._sigev_un = { ._tid = gettid() },
// note: gettid() conceivably can fail
.sigev_signo = LOCK_TIMER_SIGNAL },
&timer);
// detect and handle errors ...
result = timer_settime(timer, 0,
& (struct itimerspec) { .it_value = { .tv_sec = to_secs } },
NULL);
result = fcntl(fd, F_SETLKW, lock_info);
// detect and handle errors (other than EINTR) ...
// on EINTR, may want to check that the timer in fact expired
result = timer_delete(timer);
// detect and handle errors ...
return result;
}
这符合我的预期。
try_lock
函数本身修改其所选信号的配置是没有用的(而且可能是危险的)。timer_*
接口(interface)提供 POSIX 间隔计时器,但指定特定线程接收来自此类计时器的信号的规定是 Linux 特定的。timer_*
函数链接 -lrt
。struct sigevent
不符合其自己的文档(至少在相对较旧的版本 2.17 中)这一事实。文档声称 struct sigevent
有一个成员 sigev_notify_thread_id
,但实际上它没有。相反,它有一个未记录的 union 体,其中包含相应的成员,并且它提供了一个宏来弥补差异——但该宏在指定的初始值设定项中不能用作成员指定符。fcntl
锁在每个进程的基础上运行。因此,同一进程的不同线程不能通过这种锁相互排斥。此外,同一进程的不同线程可以修改通过其他线程获得的 fcntl()
锁,无需任何特殊努力或任何线程通知。fcntl()
将返回 EINTR
如果被任何 不终止线程的信号中断。因此,您可能希望使用一个信号处理程序来设置一个肯定的每线程标志,您可以通过该标志验证是否收到了实际的计时器信号,以便在它被不同的信号中断时重试锁定。EINTR
锁定失败的情况下时间实际上已到期.关于c - linux fcntl文件锁定超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57047510/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
Linux 管道可以缓冲多少数据?这是可配置的吗? 如果管道的两端在同一个进程中,但线程不同,这会有什么不同吗? 请注意:这个“同一个进程,两个线程”的问题是理论上的边栏,真正的问题是关于缓冲的。 最
我找到了here [最后一页] 一种有趣的通过 Linux 启动 Linux 的方法。不幸的是,它只是被提及,我在网上找不到任何有用的链接。那么有人听说过一种避免引导加载程序而使用 Linux 的方法
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我试图了解 ld-linux.so 如何在 Linux 上解析对版本化符号的引用。我有以下文件: 测试.c: void f(); int main() { f(); } a.c 和 b.c:
与 RetroPie 的工作原理类似,我可以使用 Linux 应用程序作为我的桌面环境吗?我实际上并不需要像实际桌面和安装应用程序这样的东西。我只需要一种干净简单的方法来在 RaspberryPi 上
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
有什么方法可以覆盖现有的源代码,我应该用 PyQt、PyGTK、Java 等从头开始构建吗? 最佳答案 如果您指的是软件本身而不是它所连接的存储库,那么自定义应用程序的方法就是 fork 项目。据我所
我的情况是:我在一个磁盘上安装了两个 linux。我将第一个安装在/dev/sda1 中,然后在/dev/sda2 中安装第二个然后我运行第一个系统,我写了一个脚本来在第一个系统运行时更新它。
我在 i2c-0 总线上使用地址为 0x3f 的系统监视器设备。该设备在设备树中配置有 pmbus 驱动程序。 问题是,加载 linux 内核时,这个“Sysmon”设备没有供电。因此,当我在总线 0
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正试图在 linux 模块中分配一大块内存,而 kalloc 做不到。 我知道唯一的方法是使用 alloc_bootmem(unsigned long size) 但我只能从 linux 内核而不是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有 .sh 文件来运行应用程序。在该文件中,我想动态设置服务器名称,而不是每次都配置。 我尝试了以下方法,它在 CentOS 中运行良好。 nohup /voip/java/jdk1.8.0_71/
我是在 Linux 上开发嵌入式 C++ 程序的新手。我有我的 Debian 操作系统,我在其中开发和编译了我的 C++ 项目(一个简单的控制台进程)。 我想将我的应用程序放到另一个 Debian 操
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我使用4.19.78版本的稳定内核,我想找到带有企鹅二进制数据的C数组。系统启动时显示。我需要在哪里搜索该内容? 我在 include/linux/linux_logo.h 文件中只找到了一些 Log
我知道可以使用 gdb 的服务器模式远程调试代码,我知道可以调试针对另一种架构交叉编译的代码,但是是否可以更进一步,从远程调试 Linux 应用程序OS X 使用 gdbserver? 最佳答案 当然
是否有任何可能的方法来运行在另一个 Linux 上编译的二进制文件?我知道当然最简单的是在另一台机器上重建它,但假设我们唯一能得到的是一个二进制文件,那么这可能与否? (我知道这可能并不容易,但我只是
我是一名优秀的程序员,十分优秀!