【问题标题】:When does the routine passed to pthread_create start?传递给 pthread_create 的例程何时开始?
【发布时间】:2017-06-23 04:41:06
【问题描述】:

给定以下代码

#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;
}

例程总能得到正确的tid吗?

当然我可以使用 pthread 来获取自己的 ID,但我只是想知道例程什么时候运行。

【问题讨论】:

  • “传递给 pthread_create 的例程何时开始?”,在调用 pthread_create() 之后?你的问题不清楚。 “例行程序总能得到正确的时间吗?”你什么意思?
  • 您将 &amp;tid 作为 pthread_create 的第一个参数(pthread_create 应该存储新线程 ID 的位置)和 pthread_create 的第四个参数(被传递到pt_routine)。这听起来就像您在询问pt_routine 是否有可能在pthread_create 实际将线程的ID 存储在该地址之前运行并取消引用它的arg。对吗?

标签: c pthreads posix


【解决方案1】:

嗯,其实有2个问题:

  • 哪个线程将首先执行
  • 在新线程开始之前会保存线程 ID。

这个答案涉及 Linux,因为我没有任何其他可用的平台。第一个问题的答案可以在in the manuals找到:

除非是实时的 在调用 pthread_create(),不确定是哪个线程——调用者还是 新线程——接下来会执行。

所以很明显,在您的情况下,哪个线程将首先运行是不确定的。现在,另一个问题是pthread_create 是如何实现的——如果它能够以某种方式创建一个休眠线程,先存储它的 id,然后再启动它?

好吧,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

现在,线程 id 似乎与来自clone 调用的指针一起存储,但很明显child_tidptr 并不引用tid地址,好像我打印的一样,地址不一样;这是pthread 库中的一些内部变量;并且tid 将在clone 系统调用在父线程中返回后更新。

确实,pthread_self 说了以下内容:

pthread_self()返回的线程ID不是一回事 作为调用 gettid(2) 返回的内核线程 ID。

这确认内核线程 ID 与 pthread_ts 不同

因此,除了 POSIX spec 不支持这一点之外,实际上在 Linux 平台上也没有这样的保证 - tid 需要在父线程中设置clone 返回后,否则 parent 不会立即知道子进程的线程 id - 但这也意味着如果子进程在返回后是第一个执行的,那么线程 id 可能还没有设置。

【讨论】:

    【解决方案2】:

    pt_thread() 将在pthread_create() 被调用后的某个任意点开始执行——这包括它可能在pthread_create() 返回调用代码之前开始运行。并且无法保证pthread_create() 实现会在线程开始执行之前更新tid 变量。

    因此,您的代码中没有任何内容可以确保pt_routine() 将正确读取tid 值。您需要使用某种同步来确保在没有数据竞争的情况下正确发生。或者你可以让线程调用pthread_self()

    参见the POSIX spec for pthread_create()的“应用程序使用”部分:

    在新创建的线程开始执行之前,不要求创建线程的 ID 可用。调用线程可以通过pthread_create()函数的返回值获取创建线程的ID,新创建的线程可以通过调用pthread_self获取其ID

    【讨论】:

    • 来自 linux 手册页的另一个 quote:“有关 pthread_create() 在 *thread 返回的线程 ID 的更多信息,请参见 pthread_self(3)。除非采用实时调度策略,否则在调用 pthread_create(),不确定哪个线程(调用者或新线程)接下来将执行。”
    猜你喜欢
    • 2015-12-24
    • 2023-03-15
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 2023-03-31
    相关资源
    最近更新 更多