在linux中,线程与进程最大的区别就是是否共享同一块地址空间,而且共享同一块地址空间的那一组线程将显现相同的PID号。
在实际编程应用中,我们会很容易发现并证明,一组同源线程的PID都是一样的,但它们的PID真的一样么?
在linux中,线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源:
-
clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND,0);
上面的代码产生的结果和调用fork()差不多,只是父子俩共享地址空间、文件系统资源、文件描述符和信号处理程序。换个说法就是,新建的进程和它的父进程就是流行的所谓线程。 对比一下,一个普通的fork()的实现是:
而vfork()的实现是:
-
clone(CLONE_VFORK|CLONE_VM|SIGCHLD,0);
传递给clone()的参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类。下面列举部分clone()参数标志,这些是在<linux/sched.h>中定义的。 CLONE_FILES 父子进程共享打开的文件 CLONE_FS 父子进程共享文件系统信息 CLONE_SIGHAND 父子进程共享信号处理函数 CLONE_VM 父子进程共享地址空间 CLONE_VFORK 调用vfork(),所以父进程准备睡眠等待子进程将其唤醒下面用一段程序测试一下,代码如下:这段测试程序是主线程创建10个线程,并分别打印PID及TID。
-
#include<stdio.h>
-
#include<stdlib.h>
-
#include<pthread.h>
-
#include<unistd.h>
-
#include<sys/types.h>
-
#include<string.h>
-
-
pthread_ttid[10];
-
-
void*thread_handler(void*arg)
-
{
-
printf("tid%d:%u,pid:%u\n",(int)arg,(unsigned)pthread_self(),
-
(unsigned)getpid());
-
while(1){
-
sleep(1);
-
}
-
returnNULL;
-
}
-
-
intmain(void)
-
{
-
inti,ret;
-
pid_tpid;
-
printf("main tid:%u,pid:%u\n",(unsigned)pthread_self(),
-
(unsigned)getpid());
-
for(i=0;i<10;i++){
-
if((ret=pthread_create(&tid[i],NULL,thread_handler,
-
(void*)i))!=0){
-
fprintf(stderr,"pthread_create:%s\n",
-
strerror(ret));
-
exit(1);
-
}
-
}
-
sleep(3);
-
pid=fork();
-
if(pid==0){
-
printf("son tid:%u,pid:%u\n",(unsigned)pthread_self(),
-
(unsigned)getpid());
-
while(1);
-
sleep(1);
-
}
-
while(1)
-
sleep(2);
-
exit(0);
-
}
编译运行:
-
zx@zhangxu:~/lianxi/apue$gcc-o
test pthreadid.c-lpthread
-
zx@zhangxu:~/lianxi/apue$./test
-
main tid:3077888816,pid:2418
tid0:3077880688,pid:2418
tid1:3069487984,pid:2418
tid2:3061095280,pid:2418
tid3:3052702576,pid:2418
tid4:3044309872,pid:2418
tid5:3035917168,pid:2418
tid6:3027524464,pid:2418
tid7:3019131760,pid:2418
tid8:3010739056,pid:2418
tid9:3002346352,pid:2418
son tid:3077888816,pid:2429
从结果可以看出,测试程序中所有线程的PID都相同。在另一个终端调用pstree -pu
-
├─gnome-terminal(1624,zx)─┬─bash(1628)
│ ├─bash(1704)───pstree(2430)
│ ├─bash(1927)───test(2418)─┬─test(2429)
│ │ ├─{test}(2419)
│ │ ├─{test}(2420)
│ │ ├─{test}(2421)
│ │ ├─{test}(2422)
│ │ ├─{test}(2423)
│ │ ├─{test}(2424)
│ │ ├─{test}(2425)
│ │ ├─{test}(2426)
│ │ ├─{test}(2427)
│ │ └─{test}(2428)
从中可以看出,每个线程的PID其实是不同的,因为测试程序是理想状态,只有一个主线程在创建线程,所以PID的值都是连续的。
参考资料:《linux内核设计与实现》
----
转自:linux线程的线程ID与其进程ID
分享到:
相关推荐
在本实验中,我们将学习 Linux 系统中的多线程编程,了解进程概念和 Linux 可执行文件结构。我们将通过编写多个程序,使用系统调用 fork() 创建多个子进程,并观察进程之间的并发执行。 一、理解进程概念 在操作...
在Linux操作系统下,多线程编程是一种常见的编程技术,它允许多个执行流在同一进程中并发运行,从而提高程序的响应速度、充分利用多核处理器资源以及改善程序结构。Linux下的多线程实现基于POSIX线程接口(pthread)...
现代操作系统(如Windows、Linux等)均提供了良好的多线程支持。开发者需要考虑以下几点: - **操作系统特性**:不同的操作系统对多线程的支持程度不同,了解目标操作系统的特点可以帮助更好地设计程序结构。 - **...
本节将深入探讨Linux中的进程、线程和轻量级进程,以及与其相关的进程描述符、状态转换、PID管理和内核堆栈等重要知识点。 1. **进程** 是程序执行的一个实例,它是一个动态的概念,表现为有限状态机的迁移过程。...
`fork()`函数的特性在于,一旦调用成功,它将返回两次:一次在父进程中,返回值是新创建的子进程的进程ID(PID),另一次在子进程中,返回值为0。这种设计使得父进程和子进程可以独立执行不同的代码路径。 在上述...
然后,它将父进程的所有内容复制到新进程中,除了少数几个特定的标识,如进程ID(PID)和返回值。因此,尽管两个进程有相同的代码和初始数据,但它们是独立的实体,可以执行不同的操作。 以下是一个简单的`fork()`...
这个过程需要考虑到并发执行的多个进程,确保在多线程环境下的正确性和原子性。 了解`getpid`的使用和内部实现对于开发者来说非常重要,尤其是在编写需要进行进程管理或协作的程序时。例如,在进程间通信(IPC)中...
它可以显示当前运行的进程ID、进程的用户、CPU使用率、内存使用情况等。而“xnb”可能是一个特定的选项或者扩展,这在标准的“ps”命令中并不常见,可能是一个自定义的版本或者特定环境下的扩展功能。 如果“xnb”...
4. **检查服务状态**:有时,脚本会包含检查服务是否已启动的逻辑,这可以通过检查进程ID或监听端口来实现。 ```bash pid=$(pgrep -f "your-app-name") if [ -z "$pid" ]; then echo "Service is not running." ...
kill -F 进程名 加-F参数后强制结束某进程(为系统的附加工具,默认是没有安装的,在安装目录的Support/tools文件夹内) del -F 文件名 加-F参数后就可删除只读文件,/AR、/AH、/AS、/AA分别表示删除只读、隐藏、...
- **线程安全方法**:为了避免多线程环境下的数据竞争问题,开发者需要确保关键代码路径的线程安全性。 11. **组件生命周期** - **Activity 生命周期**:包括 `onCreate()`、`onStart()`、`onResume()`、`onPause...
在多线程或多进程环境中,可能会出现对Redis的并发访问问题,解决方法包括: - **使用Redis的事务**:通过MULTI/EXEC指令序列化多个命令的执行。 - **使用Lua脚本**:在Redis服务器端执行Lua脚本,确保操作的一致性...
- **线程**:是CPU调度和执行的基本单位,属于同一进程的线程共享该进程的资源。 #### ICMP报文类型及功能 - **终点不可达**:指示目标网络或主机不可达。 - **源站抑制**:用于通知发送方降低数据传输速率。 - **...