【问题标题】:Setting thread's name in another thread on macOS在 macOS 上的另一个线程中设置线程的名称
【发布时间】:2018-08-04 18:34:30
【问题描述】:

函数 pthread_setname_np 在 macOS 上只接受一个参数,并设置当前线程的线程名称。基本上它的作用是调用 proc_info 系统调用如下(代码来自Apple open-source 页面):

__proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, 0, name, length);

但是 NSThread 的 setName 方法是(唯一)在另一个线程中设置线程名称的方法(Xcode 和 lldb 显示新名称)。由于 NSThread 的实现没有可用的源代码,我反汇编了 Foundation 框架(/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation)并找到了这段代码:

如您所见,它仅使用 pthread_setname_np(似乎只有在 self == [NSThread currentThread] 时才调用它)并且不直接调用 proc_info。我尝试使用 dtruss 调试 setName 并发现如果从不同的线程调用 proc_info 系统调用实际上是在 setName 事件上调用的,当对 setName 的调用添加到代码中时,我得到以下行:

proc_info(0x5, 0x15496, 0x2)         = 0 0

那么实际上有没有办法在不同的线程中设置线程名称?它是如何完成的?而为什么setName的反汇编只有pthread_setname_np调用呢?

附言。我知道可以使解决方法(蹦床)从不同的线程传递名称,然后在必须更改名称的线程内调用 pthread_setname_np,但我对 setName 的实际实现方式感兴趣。

编辑: 我从两个不同的线程调用 setName,dtruss 输出以下内容(第一列是 pid/tid),0x4f800a (5210122) 是我要更改名称的线程的 tid:

37555/0x4f800a:        37       6      0 thread_selfid(0x0, 0x0, 0x0)        = 5210122 0
37555/0x4f800a:       218      11      5 proc_info(0x5, 0x92B3, 0x2)    = 0 0
37555/0x4f800a:       243       6      2 proc_info(0x5, 0x92B3, 0x2)    = 0 0

这意味着 proc_info 调用以某种方式挂接到线程的代码中。看起来像是一个 Objective-C 运行时特性。

【问题讨论】:

    标签: objective-c c multithreading macos pthreads


    【解决方案1】:

    我很确定单个 api 无法在另一个线程上设置线程名称...pthread_setname_np 只接受一个参数,因此您将不得不以某种方式将其传递给线程.. . 当你生成线程时,你可以传入一个值,该值可以是任何指针(类型void *),所以你可以传入一个指向:

    struct {
        void * normalArg;
        const char * name;
    }named_thread_arg;
    

    如果你在开始的时候不知道名字,你可以做一个双星

    struct {
        void * normalArg;
        volatile char ** name;
    }named_later_thread_arg;
    

    将其设置为NULL,然后检查您的工作循环,如果已设置,则可以从那里设置:

    if (arg->name){
        pthread_setname_np(*arg->name);
        arg->name=NULL; // (so you dont set it every loop, or do if you want to change)
    }
    

    【讨论】:

    • 正如我在 post scriptum 中已经说过的那样,我知道这种解决方法,但似乎 NSThread 的 setName 通过对 proc_info 的系统调用来做到这一点(参见 dtruss 的日志)。
    • @ElvissStrazdins,如果你对它调用可能随时更改的未记录方法感到满意......你可以调用imp__stubs__pthread_set_name_np并猜测传入的参数......可能是pthread_t * thread和@ 987654329@
    • 你是对的。请参阅我关于 Objective-C 如何做到这一点的答案(在目标线程中调用 pthread_setname_np)。
    【解决方案2】:

    我在 __proc_info 上添加了一个断点并使用 lldb 运行测试应用程序,在 break 时得到以下堆栈:

    frame #0: 0x00007fff78401c3c libsystem_kernel.dylib`__proc_info
    frame #1: 0x00007fff7853e0b0 libsystem_pthread.dylib`pthread_setname_np + 88
    frame #2: 0x00007fff52a7ae88 Foundation`__NSThread__start__ + 1101
    frame #3: 0x00007fff7853d6c1 libsystem_pthread.dylib`_pthread_body + 340
    frame #4: 0x00007fff7853d56d libsystem_pthread.dylib`_pthread_start + 377
    frame #5: 0x00007fff7853cc5d libsystem_pthread.dylib`thread_start + 13
    

    这意味着 pthread_setname_np 实际上是在 NSThread 启动方法中调用的。我在启动 NSThread 后添加了一个睡眠,然后调用了 setName 并且名称没有更改,因为线程已经启动。这解释了一切。所以不可能在不同的线程上更改线程名称。

    【讨论】:

      猜你喜欢
      • 2011-04-02
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-23
      • 2017-12-25
      • 1970-01-01
      相关资源
      最近更新 更多