gpt4 book ai didi

c - 在Docker容器内使用成员

转载 作者:行者123 更新时间:2023-12-02 18:13:28 26 4
gpt4 key购买 nike

我有一个需要能够处理SIGTERM的程序。为此,我需要sigterm处理程序将设置的sig_atomic_t全局标志。为了使主代码能够可靠地读取该变量,我需要在处理程序和主代码中都使用一个中间符。

正如我现在所拥有的,它是这样的:

static  int             mb_cmd;
static sig_atomic_t sigterm;


static
int mb_init(void);
static
int sigterm_init(void);
static
void sigterm_handler(int sig);


inline
int membarrier(int cmd, int flags)
{
return syscall(__NR_membarrier, cmd, flags);
}


int main(void)
{
int status;

status = 1;
if (sigterm_init())
goto err;

do {
// do stuff
asm volatile ("" : : : "memory");
} while (!sigterm);

return 0;
err:
fprintf(stderr, "ERROR: main(): %i\n", status);
perrorx(NULL);

return status;
}


static
int mb_init(void)
{
static bool done = false;
int cmd;
int status;

if (done)
return 0;

status = 1;
cmd = membarrier(MEMBARRIER_CMD_QUERY, 0);
if (cmd < 0)
goto err;

if (cmd & MEMBARRIER_CMD_PRIVATE_EXPEDITED) {
status = 2;
mb_cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED;
if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0))
goto err;
} else if (cmd & MEMBARRIER_CMD_GLOBAL_EXPEDITED) {
status = 3;
mb_cmd = MEMBARRIER_CMD_GLOBAL_EXPEDITED;
if (membarrier(MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, 0))
goto err;
} else {
mb_cmd = MEMBARRIER_CMD_GLOBAL;
}

status = 4;
if (membarrier(mb_cmd, 0))
goto err;
done = true;
return 0;
err:
fprintf(stderr, "ERROR: mb_init(): %i\n", status);
return status;

}

static
int sigterm_init(void)
{
struct sigaction sa = {0};
int status;

status = 1;
if (mb_init())
goto err;

sigterm = false;
membarrier(mb_cmd, 0);

status++;
sigemptyset(&sa.sa_mask);
sa.sa_handler = &sigterm_handler;
if (sigaction(SIGTERM, &sa, NULL))
goto err;
return 0;
err:
fprintf(stderr, "ERROR: sigterm_init(): %i\n", status);
return status;
}

static
void sigterm_handler(int sig)
{

(void)sig;

sigterm = true;
membarrier(mb_cmd, 0);
}

当我在计算机上运行程序时,它可以正常工作,但是在docker上,它显示以下错误( errno为1):
ERROR: mb_init(): 1
ERROR: sigterm_init(): 1
ERROR: main(): 1
./rob:
rob.c:184:
main():
E1 - Operation not permitted

如何在应该在docker上运行的程序中使用内存屏障?

最佳答案

And for the main code to be able to reliably read that variable, I need to use a membarrier both in the handler and in the main code.



不,只需将其设置为volatile sig_atomic_t即可。 ISO C保证您的代码可以工作,而无需在源代码中编写任何显式的障碍。 (基本类似于具有mo_relaxed顺序的无锁 _Atomic,但有序wrt和其他 Volatile 访问除外。)

而且,如果确实需要内存屏障,则不需要 membarrier系统调用,只需使用 asm("" ::: "memory")强制存储或加载至少在循环中发生一次。

如果您有另一个线程从内存中进行弱排序的加载,但无法对其进行优化(退出循环),则 membarrier()可能会很有用。如果您在生产者线程中的两个存储之间进行操作,则 membarrier()可能会将另一个内核上的宽松负载有效地转换为获取负载。

由于您已经在读取器中使用了编译时完整屏障(以防止非 Volatile 负载脱离循环),因此检查exit_now或keep_running标志没有排序顺序。其他代码,则不需要。

ISO C首先只保证 volatile sig_atomic_t的任何内容,而不是简单的 sig_atomic_t(通常只是 int)。 使用sig_atomic_t的唯一原因是将它与volatile一起使用。

实际上, volatile int甚至对其他线程可见,而不仅仅是在信号处理程序和暂停运行该信号处理程序的线程之间。 (因为真正的C实现在高速缓存相关的硬件上运行,并且不进行硬件竞争检测等),但是到那时,您只是在滚动自己的无锁原子,而应该使用 _Atomic int。另请参见 https://electronics.stackexchange.com/questions/387181/mcu-programming-c-o2-optimization-breaks-while-loop/387478#387478,以了解单线程和中断(或信号)处理程序之间的原子性。

并参阅 When to use volatile with multi threading?-基本上从不使用 _Atomic中的C11 stdatomic.h。我的回答解释了为什么它在实践中确实起作用,以及发生了什么。

关于c - 在Docker容器内使用成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60494920/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com