简体   繁体   English

传递给pthread_create的例程何时开始?

[英]When does the routine passed to pthread_create start?

Given the following code 给出以下代码

#include <pthread.h>

void *pt_routine(void *arg)
{
    pthread_t *tid;
    tid = (pthread_t *) arg;
    /* do something with tid , say printf?*/
    /*
    printf("The thread ID is %lu\n", *tid);
    */
    return NULL;
}

int main(int argc, char **argv)
{
    int rc;
    pthread_t tid;
    rc = pthread_create(&tid, NULL, pt_routine, &tid);
    if (rc)
    {
        return 1;
    }
    printf("The new thread is %lu\n", tid);
    pthread_join(tid, NULL);
    return 0;
}

Can the routine ALWAYS get the right tid ? 常规总能得到正确的tid

Of course I could use pthread to fetch self ID but I just wonder when does the routine run. 当然,我可以使用pthread来获取自身ID,但是我只是想知道例程何时运行。

Well, there are actually 2 questions: 好吧,实际上有两个问题:

  • which thread will execute first 哪个线程将首先执行
  • will the thread id be saved before the new thread starts. 将在新线程启动之前保存线程ID。

This answer concerns Linux, as I don't have any other platforms available. 这个答案与Linux有关,因为我没有其他可用的平台。 The answer to the first question can be found in the manuals : 第一个问题的答案可以在手册中找到:

Unless real-time scheduling policies are being employed, after a call to pthread_create() , it is indeterminate which thread—the caller or the new thread—will next execute. 除非采用实时调度策略,否则在调用pthread_create() ,不确定哪个线程(调用者或新线程)接下来将执行。

So it is clear that in your case, it is indeterminate which thread will actually run first. 因此很明显,在您的情况下,不确定哪个线程将首先运行。 Now, another question is how is pthread_create implemented - if it could somehow create a dormant thread, storing its id first, and then later starting it? 现在,另一个问题是如何实现pthread_create如果它可以以某种方式创建一个休眠线程,先存储其ID,然后再启动它?

Well, linux creates the new thread using the clone system call: 好吧,Linux使用clone系统调用创建了新线程:

clone(child_stack=0x7f7b35031ff0, 
      flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM
          |CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
      parent_tidptr=0x7f7b350329d0,
      tls=0x7f7b35032700,
      child_tidptr=0x7f7b350329d0) = 24009

Now, it seems that the thread id is stored with a pointer from the clone call, but it seems clear that child_tidptr doesn't refer to the address of tid , as if I print it, the the address is different; 现在,似乎线程ID是与clone调用中的指针一起存储的,但显然child_tidptr并没有引用tid地址 ,就像我打印它一样,该地址是不同的。 this is some internal variable within the pthread library; 这是pthread库中的一些内部变量; and tid would be updated after the clone system call returns in the parent thread. clone系统调用在父线程中返回tid将被更新。

And indeed, pthread_self says the following: 实际上, pthread_self表示以下内容:

The thread ID returned by pthread_self() is not the same thing as the kernel thread ID returned by a call to gettid(2) . pthread_self()返回的线程ID与对gettid(2)的调用返回的内核线程ID不同。

This confirms that the kernel thread ids are distinct from pthread_t s 这确认内核线程ID与pthread_t不同

Thus, in addition to this not being supported by the POSIX spec , there is no such guarantee on the Linux platform in practice - the tid will need to be set in the parent thread after clone returns, otherwise the parent wouldn't immediately know the thread id of the child - but this also means that if the child is the first to execute after the return, then the thread id might not be set there yet. 因此,除了POSIX规范不支持此功能外,实际上在Linux平台上也没有这样的保证- clone返回后,需要在父线程中设置tid ,否则父级不会立即知道子代的线程ID-但这也意味着,如果子代是返回后第一个执行的子代,则可能尚未在此处设置线程ID。

pt_thread() will begin execution at some arbitrary point after pthread_create() is called - and that includes that it might start running before pthread_create() returns to the calling code. pt_thread()将在调用pthread_create()之后的任意点开始执行-包括可能在pthread_create()返回调用代码之前开始运行。 And there is no guarantee made that the pthread_create() implementation will update the tid variable before the thread starts execution. 并且不能保证pthread_create()实现将在线程开始执行之前更新tid变量。

So there is nothing in your code that ensures that pt_routine() will read the tid value properly. 因此,您的代码中没有什么可以确保pt_routine()可以正确读取tid值。 You would need to use some sort of synchronization to ensure that occurs properly without a data race. 您将需要使用某种同步来确保在没有数据争用的情况下正确进行。 Or you could have the thread call pthread_self() . 或者,您可以使用线程调用pthread_self()

See the "Application Usage" section of the POSIX spec for pthread_create() : 请参阅POSIX规范的“应用程序使用情况”部分中pthread_create()

There is no requirement on the implementation that the ID of the created thread be available before the newly created thread starts executing. 在实现上,不需要在新创建的线程开始执行之前可用已创建线程的ID。 The calling thread can obtain the ID of the created thread through the return value of the pthread_create() function, and the newly created thread can obtain its ID by a call to pthread_self 调用线程可以通过pthread_create()函数的返回值获取创建的线程的ID,而新创建的线程可以通过调用pthread_self来获取其ID。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM