进程和线程是包含与被包含的关系,一个进程至少有一个线程。进程有独立的代码和数据空间,线程共享所属进程的资源,但是有独立的栈和程序计数器。
Linux系统中,可以调用getpid()函数获取进程ID,但该进程中每个线程调用getpid()返回的都是同一个值。当需要获取线程的真实PID时,可以调用syscall(SYS_gettid)。
示例程序
下面代码中,只做了两件事:
1)signal()注册信号处理函数,捕获到SIGABRT、SIGPIPE等信号时,打印getpid()返回的PID、syscall(SYS_gettid)返回的真实PID、pthread_self()返回的线程ID;
2)创建一个线程;
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>
void signal_handler(int signum)
{
printf("<getpid:%d, SYS_gettid:%ld, pthread id:%ld> handling signal:%d\n",
getpid(), syscall(SYS_gettid), pthread_self(), signum);
}
static void *listen_thread(void *data)
{
printf("thread pid:%ld\n", syscall(SYS_gettid));
while(1)
{
sleep(2);
}
}
int main(int argc, char *argv[])
{
pthread_t td;
pthread_attr_t attr;
signal(SIGABRT , signal_handler);
signal(SIGBUS , signal_handler);
signal(SIGFPE , signal_handler);
signal(SIGSEGV , signal_handler);
signal(SIGPIPE , signal_handler);
signal(SIGTERM , signal_handler);
signal(SIGSTKFLT, signal_handler);
signal(SIGCHLD , signal_handler);
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 256 * 1024);
pthread_create(&td, &attr, listen_thread, NULL);
pthread_attr_destroy(&attr);
printf("getpid:%d\n", getpid());
while(1)
{
sleep(2);
}
return 0;
}
编译运行示例如下:
从上图可以看到,
- 程序运行时,getpid()和终端键入ps命令都可以看到程序进程ID是3082,kill命令给PID=3082进程发送信号时,main入口的主线程捕获了信号,pthread_create创建的线程listen_thread并不能捕获到该信号;
- 于是syscall(SYS_gettid)派上用场:listen_thread线程调用syscall(SYS_gettid)返回了3083,kill命令给PID=3083进程发送信号时,listen_thread线程成功捕获信号,而主线程没有;