4

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

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 返回一个非零数字。

4

5 回答 5

4

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

你的returnVal用法不对

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

pthread_join(aThread[i], NULL);

如果您想知道该void**参数的用途是什么,它是一个存储 void*线程进程返回值的地方。回想一下 pthread thread-proc 看起来像这样:

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]);
    }
}
于 2013-10-10T04:37:02.697 回答
4

当函数失败时(即在任何 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) 有一个 glibc 扩展printf提供了一个%m转换说明符,它的作用类似于strerror但少了一点麻烦和大惊小怪。这将是最不便携的。

获得描述后,您可以轻松查看失败调用的手册页,它们将提供有关调用失败原因的更多提示。查理伯恩斯已经发布了pthread_join可能失败的原因。

于 2013-10-10T04:31:06.873 回答
0

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

返回值 如果成功,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.
于 2013-10-10T03:48:05.177 回答
0

进一步来说::

int retVal = pthread_create(&myThread, NULL,myThreadFn, NULL);
printf("error joining thread: %d\n", retVal);
于 2015-07-28T09:51:26.200 回答
0

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

返回值

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

如果需要通过strerror()strerror_r()%m printf 格式(后者是 GLIBC 扩展)等函数输出错误,则必须使用失败服务的返回码或在错误分支中更新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()不是)
于 2020-11-03T13:22:11.043 回答