【问题标题】:How do I get the error code from pthread_join()?如何从 pthread_join() 获取错误代码?
【发布时间】:2013-10-17 16:16:08
【问题描述】:

以下代码无法加入 pthreads,并打印消息“加入失败”。如何获取有关故障及其原因的更多信息?

pthread_t aThread[MAX_LENGTH];
    int errCode[MAX_LENGTH];
    char returnVal;    
for(int i = 0; i < MAX_LENGTH; i++)
    {

        if((errCode[i] = pthread_create(&aThread[i], NULL, &findMatch, &fpArgs)) != 0)
            printf("error creating thread %d\n", errCode[i]);
        if(!pthread_join(aThread[i], (void**)&returnVal))
            printf("join failed\n i is %d", i);
    }

编辑: 实际上加入返回了no error,我犯了一个错误。 if 语句不应该有 !,因为如果存在计算结果为 true 的问题,则 join 返回一个非零数字。

【问题讨论】:

  • 您将returnVal 地址转换为void** 是未定义行为。除非sizeof(char) == sizeof(void*) 在你的系统上(我可以向你保证它是不是)它看起来不像你在使用它,NULL 是一个可行的选择,所以你可能只是pthread_join(aThread[i], NULL); 此外,pthread_join 返回零 (0) 成功,因此使用 ! 测试它是否失败是倒退的。最后,无论如何你都不想这样做,你想全部启动它们,然后加入它们。你在这里所拥有的实际上并不比单线程好。

标签: c multithreading pthreads errno pthread-join


【解决方案1】:

我在评论中指出了这一点,但它值得放大。

您的returnVal 使用错误

pthread_join api 需要一个void**,它是一个指向void* 的指针。与void* 不同,void** 并不同样普遍。它是一个特定类型的指针,因此您应该只传递一个类似类型的地址。但是,无论如何您都没有使用它,所以我现在建议您只需传递 NULL。正如所写,它是未定义的行为。我几乎可以向您保证sizeof(char),您提供给它的地址的可写大小,和sizeof(void*),它期望可用的大小,不相同。现在考虑这个:

pthread_join(aThread[i], NULL);

如果您想知道void** 参数的用途是什么,它是一个存储来自线程进程的void* 返回值的地方。回想一下 pthread 线程过程如下所示:

void* thread_proc(void* args)
// ^----- this is what is stashed in the pthread_join second parameter

你失败测试的逻辑是倒退的

pthread_join 函数在 成功 时返回 0;不是失败。


您实际上并没有运行并发线程

线程并发仅仅意味着您的线程同时运行。但你的没有。您启动一个线程,然后等待它结束,然后启动一个线程,然后等待它结束,等等。这实际上并不比简单地调用一个更好(实际上,实际上更糟)功能。如果你想让你的线程同时运行你的逻辑应该是这样的:

pthread_t aThread[MAX_LENGTH];
int errCode[MAX_LENGTH] = {0};

for (int i = 0; i < MAX_LENGTH; i++)
{
    if((errCode[i] = pthread_create(&aThread[i], NULL, &findMatch, &fpArgs)) != 0)
        printf("error creating thread %d, error=%d\n", i, errCode[i]);
}

for (int i = 0; i < MAX_LENGTH; i++)
{
    // note the check for errCode[i], which is only non-zero 
    //  if the i'th thread failed to start
    if(errCode[i] == 0)
    {
        errCode[i] = pthread_join(aThread[i], NULL))
        if (errCode[i] != 0)
            printf("error joining thread %d, error=%d\n", i, errCode[i]);
    }
}

【讨论】:

    【解决方案2】:

    当函数失败时(即在任何 pthread 调用中,返回码不等于 0),它会将 errno 设置为失败原因的值。有几种方法可以获得失败代码的文本解释。

    int returnval;
    
    if((returnval = pthread_join(aThread[i], (void**)&returnVal)) != 0)
    {
        printf("error joining thread: %s\n", strerror(returnval));  //1st optiop
    
        perror("error joining thread:");  //2nd option
    
        printf("error joining thread: %m\n");  //3rd option
    
    }
    

    (1)strerror会打印出你传入的错误值的错误字符串,方便放在printf语句中。

    (2) perror 允许您传递一个小字符串,该字符串将首先打印,然后它将自动打印errno 设置的任何值的错误描述。您不需要显式传递errno。

    (3) printf 有一个 glibc 扩展,它提供了一个 %m 转换说明符,其作用类似于 strerror,但少了一点麻烦和大惊小怪。这将是最不便携的。

    获得描述后,您可以轻松查看失败调用的手册页,它们会提供更多关于调用失败原因的提示。 Charlie Burns 发布了 pthread_join 可能失败的原因。

    【讨论】:

    • 您可以将调用的返回值分配给pthread_join 到errno,但我认为pthread 库不会自动为您执行此操作。所以你的第一段是错误的。您可以使用returnval,因为它是errno,因此您的其余答案看起来是正确的。 (-1)
    【解决方案3】:

    我错过了什么吗?返回值告诉你错误:

    返回值 如果成功,pthread_join() 函数将返回零。否则, 将返回一个错误号来指示错误。

    错误 如果出现以下情况,pthread_join() 将失败:

     [EDEADLK]          A deadlock was detected or the value of thread speci-
                        fies the calling thread.
    
     [EINVAL]           The implementation has detected that the value speci-
                        fied by thread does not refer to a joinable thread.
    
     [ESRCH]            No thread could be found corresponding to that speci-
                        fied by the given thread ID, thread.
    

    【讨论】:

    • 你如何让它打印出它是哪一个?例如joinErr = pthread_join(aThread[i], &amp;returnVal); printf("join returned %d\n", joinErr); 总是 0
    • @Celeritas 总是零表示它成功;没有失败。
    【解决方案4】:

    更具体地说::

    int retVal = pthread_create(&myThread, NULL,myThreadFn, NULL);
    printf("error joining thread: %d\n", retVal);
    

    【讨论】:

      【解决方案5】:

      pthread 库在出错时不会设置 errno 变量。错误代码由函数返回。 Linux 下的在线手册对 pthread 函数(例如man pthread_join)非常清楚,因为“返回值”部分通常包含以下内容:

      返回值

      成功时,pthread_join() 返回 0;出错时,它返回一个错误号。

      如果您需要通过strerror()、strerror_r()或%m等函数输出错误格式(the latter is a GLIBC extension ),您必须使用失败服务的返回码或更新错误分支中的errno:

      if ((rc = pthread_join(...)) != 0) {
        errno = rc;
        fprintf(stderr, "pthread_join(): %m\n");
       OR
        fprintf(stderr, "pthread_join(): %m\n", strerror(errno)); // rc could be used without errno
       OR
        char err_buf[128];
        errno = rc;
        fprintf(stderr, "pthread_join(): %m\n", strerror_r(errno, err_buf, sizeof(err_buf))); // rc could be used without errno
      

      注意事项:

      • errno 是线程安全的(它位于线程本地存储中)。因此,它对于每个线程都是本地的
      • strerror_r() 和 %m 应该在多线程环境中使用,因为它们是线程安全的(strerror() 不是)李>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-28
        • 2018-11-16
        • 2020-09-18
        • 2023-03-22
        • 2017-10-12
        • 2021-09-06
        • 2013-05-01
        • 2020-04-05
        相关资源
        最近更新 更多