gpt4 book ai didi

c - 如何在linux中引发因EINTR而失败的semop调用?

转载 作者:行者123 更新时间:2023-11-30 16:32:38 26 4
gpt4 key购买 nike

我正在尝试通过 semop 调用引发 EINTR 失败。

key_t semkey;
int semid;
struct sembuf sbuf;
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
struct semid_ds ds;

/* Get unique key for semaphore. */
if ((semkey = ftok("/tmp", 'a')) == (key_t) -1) {
perror("IPC error: ftok"); exit(1);
}
/* Get semaphore ID associated with this key. */
if ((semid = semget(semkey, 0, 0)) == -1) {
/* Semaphore does not exist - Create. */
if ((semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1)
{
/* Initialize the semaphore. */
arg.val = 0;
sbuf.sem_num = 0;
sbuf.sem_op = 2; /* This is the number of runs without queuing. */
sbuf.sem_flg = 0;
if (semctl(semid, 0, SETVAL, arg) == -1
|| semop(semid, &sbuf, 1) == -1) {
perror("IPC error: semop"); exit(1);
}
}
else if (errno == EEXIST) {
if ((semid = semget(semkey, 0, 0)) == -1) {
perror("IPC error 1: semget"); exit(1);
}
goto check_init;
}
else {
perror("IPC error 2: semget"); exit(1);
}
}
else
{
/* Check that semid has completed initialization. */
/* An application can use a retry loop at this point rather than
exiting. */
check_init:
arg.buf = &ds;
if (semctl(semid, 0, IPC_STAT, arg) < 0) {
perror("IPC error 3: semctl"); exit(1);
}
if (ds.sem_otime == 0) {
perror("IPC error 4: semctl"); exit(1);
}
}

sbuf.sem_num = 0;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
while (semop(semid, &sbuf, 1) == -1)
{
if (errno != EINTR)
{
perror("IPC Error: semop"); exit(1);
break;
}
}

我得到的最多的是资源不可用失败或资源繁忙。我什至尝试在两个不同的线程或两个不同的进程中运行多个信号量。但我无法获得 EINTR 失败。当 semop 等待信号量时,我什至尝试将信号作为 SIGCHLD 发送到进程。

根据 zwol 的建议,

这是我尝试过的,但它仍然不起作用,我的意思是我无法获得 EINTR。

int g_global_variable = 0;
void *sigusr1_block_thread (void *vargp)
{
while (1)
{
sleep (10);
printf ("sigusr1_block_thread\n");
}
return NULL;
}
void *semop_wait_thread (void *vargp)
{
int sem;
struct sembuf sops[2];

if((sem = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600))==-1){
return NULL;
}
if(semctl(sem,0,SETVAL,2)==-1){
exit(1);
}

sops[0].sem_num=0;
sops[0].sem_op=-1;
sops[0].sem_flg=0;

sops[1].sem_num=0;
sops[1].sem_op=0;
sops[1].sem_flg=0;

g_global_variable = 1;
printf ("Starting semop call \n");
if(eintr_check_semop(sem, sops,2)<0)
printf("Error semop\n");

return NULL;
}

int main()
{
pthread_t tid, tid1, tid2, tid3, tid4;
sigset_t set;
int s;

pthread_create(&tid, NULL, semop_wait_thread, NULL);
pthread_create(&tid2, NULL, semop_wait_thread, NULL);
pthread_create(&tid3, NULL, semop_wait_thread, NULL);
pthread_create(&tid4, NULL, semop_wait_thread, NULL);


sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGCHLD);

s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
printf ("Error during pthread_sigmask");

pthread_create(&tid1, NULL, sigusr1_block_thread, NULL);


while (1)
{
sleep (1);
if (g_global_variable == 1)
{
sleep (10);
printf ("Send SIGUSR1/SIGCHLD signals \n");
/* Send signal */
pthread_kill( tid, SIGCHLD);
pthread_kill( tid2, SIGCHLD);
pthread_kill( tid3, SIGCHLD);
pthread_kill( tid4, SIGCHLD);
pthread_kill( tid1, SIGCHLD);
pthread_kill( tid1, SIGUSR1);
break;
}
else
continue;
}

pthread_join(tid, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_join(tid4, NULL);
return 0;
}

eintr_check_semop 只是一个检查 semop 错误和返回值的函数。如果 EINTR 它会打印相同的消息。

如果我将 sigusr1 发送到阻塞线程(t、t2、t3、t4)semop 调用中断并进入循环。

无论如何我都没有得到 EINTR。然后我检查了内核源代码。

https://elixir.bootlin.com/linux/latest/source/ipc/sem.c

在 EINTR 期间,我看到它们正在循环并且没有报告相同的情况。

最佳答案

EINTR 仅当进程在阻塞系统调用上被阻塞时接收到信号,并且该信号具有处理程序,并且该处理程序配置为中断而不是重新启动系统调用时,才会发生。 (这个原则有一些异常(exception),但它们都不涉及semop。)你的程序没有任何信号处理程序,所以EINTR不会发生,即使如果你确实向它发送信号。

我无法直接告诉你如何做到这一点,但应该有效的总体模式是:

  1. 为某些信号建立信号处理程序。如果您没有理由选择其他特定信号,请使用 SIGUSR1 。使用 sigaction 来执行此操作,而不是 signal,并且不要在 sa_flags 中包含 SA_RESTART。处理程序无需执行任何操作;它必须存在。

  2. 如果程序有多个线程,请使用 pthread_sigmask 阻止除一个线程之外的每个线程中的 SIGUSR1

  3. 在已解除阻塞的 SIGUSR1 线程中,执行将阻塞的 semop 操作(对具有非零值的信号量进行“等待零”操作)值,没有 IPC_NOWAIT)。

  4. 在上述线程在 semop 上肯定被阻塞之后,从程序中的另一个线程,使用 pthread_kill 发送 SIGUSR1 到被阻止的线程。或者,从程序外部,使用常规 kill 向整个进程发送 SIGUSR1;因为信号在一个线程中被解除阻塞,所以该线程将接收到该信号。

最难的部分是确保在发送信号之前线程在 semop 上被阻塞。我不确定在没有竞争条件的情况下这是否可以从程序内部实现。

关于c - 如何在linux中引发因EINTR而失败的semop调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50065805/

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