在macOS上的另一个线程中设置线程的名称

时间:2018-02-25 01:09:00

标签: objective-c c multithreading macos pthreads

函数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)并找到了这段代码:

enter image description here

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

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

那么实际上有一种方法可以在不同的线程中设置线程名称吗?怎么做?为什么setName的反汇编只有pthread_setname_np调用?

PS。我知道可以使用变通方法(trampoline)从不同的线程传递名称,然后在必须更改名称的线程内调用pthread_setname_np,但我对如何实际实现setName感兴趣。

编辑: 我从两个不同的线程调用了setName,并且输出以下内容(第一列是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运行时功能。

2 个答案:

答案 0 :(得分:3)

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

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

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

答案 1 :(得分:0)

我很确定单个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)
}