gpt4 book ai didi

c - pthread_kill() 线程无效

转载 作者:行者123 更新时间:2023-12-01 01:26:08 29 4
gpt4 key购买 nike

我想确定一个特定的线程是否“存在”。
pthread_kill()似乎适合这项任务,至少根据其 man page .

If sig is 0, then no signal is sent, but error checking is still performed.



或者,正如我的系统手册页所说:

If sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a thread ID.



但是,当我尝试传入未初始化的 pthread_t 时,应用程序总是SEGFAULTs。

深入研究,来自 pthread_kill.c 的以下片段(来自我的工具链)似乎没有进行错误检查,只是尝试取消引用 threadid (取消引用位于 pd->tid )。
int
__pthread_kill (threadid, signo)
pthread_t threadid;
int signo;
{
struct pthread *pd = (struct pthread *) threadid;

/* Make sure the descriptor is valid. */
if (DEBUGGING_P && INVALID_TD_P (pd))
/* Not a valid thread handle. */
return ESRCH;

/* Force load of pd->tid into local variable or register. Otherwise
if a thread exits between ESRCH test and tgkill, we might return
EINVAL, because pd->tid would be cleared by the kernel. */
pid_t tid = atomic_forced_read (pd->tid);
if (__builtin_expect (tid <= 0, 0))
/* Not a valid thread handle. */
return ESRCH;

我们甚至不能依赖零作为一个好的初始化器,因为以下几点:

# define DEBUGGING_P 0
/* Simplified test. This will not catch all invalid descriptors but
is better than nothing. And if the test triggers the thread
descriptor is guaranteed to be invalid. */
# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0)

此外,我在链接的手册页中注意到以下内容(但不在我的系统上):

POSIX.1-2008 recommends that if an implementation detects the use of a thread ID after the end of its lifetime, pthread_kill() should return the error ESRCH. The glibc implementation returns this error in the cases where an invalid thread ID can be detected. But note also that POSIX says that an attempt to use a thread ID whose lifetime has ended produces undefined behavior, and an attempt to use an invalid thread ID in a call to pthread_kill() can, for example, cause a segmentation fault.



如概述 here by R.. ,我要求可怕的未定义行为。

该手册似乎确实具有误导性 - 特别是在我的系统上。
  • 有没有一种好的/可靠的方法来询问是否存在线程? (大概是因为不使用 pthread_kill() )
  • 有没有好的值可以用来初始化pthread_t类型变量,即使我们必须自己捕捉它们?

  • 我怀疑答案是雇用 pthread_cleanup_push()并保留一个 is_running我自己的旗帜,但想听听别人的想法。

    最佳答案

    我想我在开车回家的时候意识到了这一点,我怀疑很多其他人也可能会觉得这很有用......

    看起来我一直将工作人员(线程)和任务(线程正在做什么)视为一回事,而事实上,它们并非如此。

    正如我已经从问题中的代码片段中确定的那样,像 pthread_t 那样问“这个线程是否存在”是不合理的。可能只是一个指针(它肯定在我的目标上)。这几乎肯定是错误的问题。

    进程 ID、文件句柄、malloc() 也是如此'd memory 等......它们不使用唯一且从不重复的标识符,因此不是可以测试其存在的唯一“实体”。

    我在问题中提出的怀疑可能是真的 - 我将不得不使用类似 is_running 的东西。任务(不是线程)的标志。

    我想到的一种方法是使用初始化为 1 的信号量,sem_trywait() , sem_post()pthread_cleanup_push() ,如下例所示(为简洁起见,缺少清理)。

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <semaphore.h>
    #include <pthread.h>

    struct my_task {
    sem_t can_start;
    pthread_t tid;

    /* task-related stuff */
    };

    void *my_task_worker(void *arg) {
    struct my_task *task = arg;

    pthread_cleanup_push(sem_post, &(task->can_start));

    fprintf(stderr, "--- task starting!\n");
    usleep(2500000);
    fprintf(stderr, "--- task ending!\n");

    pthread_cleanup_pop(1);

    return NULL;
    }

    void my_task_start(struct my_task *task) {
    int ret;

    ret = sem_trywait(&(task->can_start));
    if (ret != 0) {
    if (errno != EAGAIN) {
    perror("sem_trywait()");
    exit(1);
    }

    fprintf(stderr, ">>> task already running...\n");
    return;
    }

    ret = pthread_create(&(task->tid), NULL, my_task_worker, task);
    if (ret != 0) {
    perror("pthread_create()");
    exit(1);
    }

    fprintf(stderr, ">>> started task!\n");

    return;
    }

    int main(int argc, char *argv[]) {
    int ret;
    struct my_task task;
    int i;

    memset(&task, 0, sizeof(0));

    ret = sem_init(&(task.can_start), 0, 1);
    if (ret != 0)
    {
    perror("sem_init()");
    return 1;
    }

    for (i = 0; i < 10; i++) {
    my_task_start(&task);
    sleep(1);
    }

    return 0;
    }

    输出:

    >>> started task!
    --- task starting!
    >>> task already running...
    >>> task already running...
    --- task ending!
    >>> started task!
    --- task starting!
    >>> task already running...
    >>> task already running...
    --- task ending!
    >>> started task!
    --- task starting!
    >>> task already running...
    >>> task already running...
    --- task ending!
    >>> started task!
    --- task starting!

    关于c - pthread_kill() 线程无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44140634/

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