Linux 平台 C/C++ 代码中设置线程名
一般來說,Linux 平臺(tái)的 C/C++ 程序可以用 prctl() 或 pthreads 的 pthread_setname_np() 接口為一個(gè)線程設(shè)置線程名。prctl() 可以用于為當(dāng)前線程設(shè)置線程名,pthread_setname_np() 則可以用于為當(dāng)前進(jìn)程的任意線程設(shè)置線程名。
prctl() 的函數(shù)聲明如下:
#include <sys/prctl.h>int prctl(int option, unsigned long arg2, unsigned long arg3,unsigned long arg4, unsigned long arg5);pthread_setname_np() 的函數(shù)聲明如下:
#define _GNU_SOURCE /* See feature_test_macros(7) */#include <pthread.h>int pthread_setname_np(pthread_t thread, const char *name);int pthread_getname_np(pthread_t thread,char *name, size_t len);如果想要通過 prctl() 為其它線程設(shè)置線程名,一般需要先將線程名放在某個(gè)地方,然后在目標(biāo)線程中拿到線程名并設(shè)下去。最常見的還是,在線程啟動(dòng)之前準(zhǔn)備好線程名,新線程啟動(dòng)之后,立即設(shè)置線程名。比如,像下面這樣:
#include <stdio.h> #include <stdlib.h> #include <sys/prctl.h> #include <pthread.h>char *thread_name1 = nullptr; char *thread_name2 = nullptr;void* thread1(void* arg) {prctl(PR_SET_NAME, thread_name1);while (1) {printf("thread1\n");sleep(1000);} }void* thread2(void* arg) {while (1) {printf("thread2\n");sleep(1000);} }int main() {pthread_t th1, th2;void* retval = NULL;thread_name1 = "THREAD1";pthread_create(&th1, NULL, thread1, NULL);pthread_create(&th2, NULL, thread2, NULL);printf("main thread\n");pthread_join(th1, &retval);pthread_join(th2, &retval); }曾經(jīng)項(xiàng)目中遇到過一個(gè)設(shè)置線程名不生效的問題,最終同事查出來是因?yàn)樵O(shè)置的線程名太長導(dǎo)致的。
glibc 的 pthread_setname_np() 函數(shù)實(shí)現(xiàn) (glibc 版本 2.34,代碼位于 glibc-2.34/nptl/pthread_setname.c) 如下:
/* pthread_setname_np -- Set thread name. Linux versionCopyright (C) 2010-2021 Free Software Foundation, Inc.This file is part of the GNU C Library.The GNU C Library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General Public License aspublished by the Free Software Foundation; either version 2.1 of theLicense, or (at your option) any later version.The GNU C Library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with the GNU C Library; see the file COPYING.LIB. Ifnot, see <https://www.gnu.org/licenses/>. */#include <errno.h> #include <fcntl.h> #include <pthreadP.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/prctl.h>#include <not-cancel.h>int __pthread_setname_np (pthread_t th, const char *name) {const struct pthread *pd = (const struct pthread *) th;/* Unfortunately the kernel headers do not export the TASK_COMM_LENmacro. So we have to define it here. */ #define TASK_COMM_LEN 16size_t name_len = strlen (name);if (name_len >= TASK_COMM_LEN)return ERANGE;if (pd == THREAD_SELF)return __prctl (PR_SET_NAME, name) ? errno : 0;#define FMT "/proc/self/task/%u/comm"char fname[sizeof (FMT) + 8];sprintf (fname, FMT, (unsigned int) pd->tid);int fd = __open64_nocancel (fname, O_RDWR);if (fd == -1)return errno;int res = 0;ssize_t n = TEMP_FAILURE_RETRY (__write_nocancel (fd, name, name_len));if (n < 0)res = errno;else if (n != name_len)res = EIO;__close_nocancel_nostatus (fd);return res; } versioned_symbol (libc, __pthread_setname_np, pthread_setname_np,GLIBC_2_34);#if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_12, GLIBC_2_34) compat_symbol (libpthread,__pthread_setname_np, pthread_setname_np,GLIBC_2_12); #endif可以看到,當(dāng)設(shè)置的線程名長度超過 16 個(gè)字符時(shí),直接返回失敗。當(dāng)通過 pthread_setname_np() 為當(dāng)前線程設(shè)置線程名時(shí),通過調(diào)用 prctl() 實(shí)現(xiàn),當(dāng)給其它線程設(shè)置線程名時(shí),則通過向 procfs 文件系統(tǒng)中,線程的 comm 文件中寫入線程名來實(shí)現(xiàn)。
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的Linux 平台 C/C++ 代码中设置线程名的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WebRTC 的 AudioSource
- 下一篇: linux 启动后台服务 nohup