Chinaunix首页 | 论坛 | 博客
  • 博客访问: 216876
  • 博文数量: 32
  • 博客积分: 410
  • 博客等级: 一等列兵
  • 技术积分: 396
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-03 16:58
文章分类

全部博文(32)

文章存档

2013年(17)

2012年(15)

我的朋友

分类: LINUX

2012-05-09 11:06:32

Dec 14, 2011   //   by   // 
误区:

之前一直认为,linux的主线程只是人为强加的概念(当一个进程创建了一些线程后,我们就把此进程主观当做主线程),在操作系统实现上并没有相关的机制或代码,今天查了一些资料,发现并不是如此。

如何标识一个进程:

(以下内容多引自《Understanding linux kernel》3.2.2节)

通常来说,每个可以独立被调度的执行上下文都有一个进程描述符,除了进程,轻量级进程也如此(为什么叫轻量级进程而不是线程,因为这是站在操作系统 的角度,而不是编程人员的角度,也是为了区分与pthread相关的概念),所以我们可以简单的认为,不管是进程还是线程都有自己的 task_struct结构。在task_struct字段中,有下面一些结构我们应该关心:

pid_t pid; pid_t tgid;
1
2
pid_t pid;
pid_t tgid;

在linux系统中,我们用pid区分每一个进程,linux给每一个进程和轻量级进程都分配一个pid,但是linux程序员希望由一个进程产生的轻量级进程具有相同的pid,这样当我们向进程发送信号时,此信号可以影响进程及进程产生的轻量级进程。

为了做到这一点,linux用了线程组(可以理解为轻量级进程组)的概念,在线程组内,每个线程都使用此线程组内第一个线程(thread group leader)的pid,并将此值存入tgid,当 我们使用getpid()函数得到进程ID时,其实操作系统返回的是task_struct的tgid字段,而非pid字段(这很重要)。如果我们调用某 个函数返回线程的ID,就应该返回的是pid,但这个函数是什么呢?不知道,也许是gettid(),但没有试验成功。

通过线程组的概念我们做到了以下两点

1.每个线程的task_struct中,pid都不同,方便系统进行调度等操作

2.每个线程的task_struct中,tgid都相同,都是第一个线程的pid,这样方便了编程人员对一个进程产生的线程进行统一管理,当然我们在线程组的每个线程内用getpid()函数时,返回相同的值。

这里有个“线程组内第一个线程(thread group leader)”的概念,怎么理解?我认为,就是创建线程的进程,也就是那个不轻量的进程,它的pid和tgid是相同的,在线程组内其他线程的pid和tgid都是不同的。

说到这,我们就可以很自然的引出“主线程”的概念,如上面所说,主线程即是“线程组内第一个线程”。

那在“误区”中为什么又说之前的理解也就是“主线程”是人为的想出来的是不对的呢?因为linux在task_struct中引入了tgid地段,用来明显的标识,若pid和tgid相同,那它就是主线程,是实实在在存在的。

 

下面我们用进程和pthread线程概念演示一下线程号和进程号区别,pthread线程应该在实现上和上面所说的线程,即轻量级进程还是有区别的,但具体有什么区别待研究。

程序演示:

#include ; #include ; void *test(void *a) { printf("Process id = %d\tChild thread id = 0x%x\n", getpid(), pthread_self()); } int main() { printf("Process id = %d\tMain thread id = 0x%x\n", getpid(), pthread_self()); pthread_t id; pthread_create(&id, NULL, test, NULL); pthread_join(id, NULL); return 0; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include ;
#include ;
void *test(void *a)
{
printf("Process id = %d\tChild thread id = 0x%x\n", getpid(), pthread_self());
}
int main()
{
printf("Process id = %d\tMain thread id = 0x%x\n", getpid(), pthread_self());
pthread_t id;
pthread_create(&id, NULL, test, NULL);
pthread_join(id, NULL);
return 0;
}

程序输出,运行了两次:

如上程序,在进程和线程内分别调用了getpid()和pthread_self()函数,getpid()返回了相同的值,而pthread_self()返回的不同。
按照之前的讲解main即为主线程,那么它pid和线程id应该是一样的,可这里我们看到pthread_self()输出的是一串十六进制数,并非如我 们所想和pid相同。查了相关资料,说phtead_self()其实返回的是phtread线程描述符的地址,即此线程struct pthread结构(在此结构中包含pid_t tid字段为线程ID)的地址,但在我的实验环境中,并不存在此结构,所以没办法验证。

另外还有一个函数gettid()用来返回线程的id,在资料中多次提到,但在我的环境中也没有。

以上理解不一定正确,欢迎讨论并指正。

看过评论后的补充说明

看了rucku关于gettid()函数使用的说明,,分别更改第5行,第9行代码如下:

printf("Process id = %d\tChild thread id = 0x%x or %d\n", getpid(), pthread_self(), syscall(SYS_gettid));
1
printf("Process id = %d\tChild thread id = 0x%x or %d\n", getpid(), pthread_self(), syscall(SYS_gettid));

printf("Process id = %d\tMain thread id = 0x%x or %d\n", getpid(), pthread_self(), syscall(SYS_gettid));
1
printf("Process id = %d\tMain thread id = 0x%x or %d\n", getpid(), pthread_self(), syscall(SYS_gettid));

此时输出为

正好验证了第一处红色文字关于线程id的猜想。

阅读(8449) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~