OS note04 -- process, thread

本文详细探讨了在Linux环境下,进程与线程的创建机制,包括fork()系统调用和pthread库函数的使用,展示了如何通过代码实例来观察进程与线程的行为,以及它们之间的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>
#include <unistd.h>
int main()
{
	printf("start from main (pid:%d)\n", (int)getpid());
	int rc;
	rc = fork();
	if( rc == 0 )
		printf("fork() 1, (pid:%d)\n", rc);
	else if( rc > 0 )
		printf("parent of [fork() 1, (pid:%d)], (pid:%d)\n", rc, (int)getpid());
	printf("back to (pid:%d)\n", (int)getpid());
	rc = fork();
	if( rc == 0 )
		printf("fork() 2, (pid:%d)\n", rc);
	else if( rc > 0 )
		printf("parent of [fork() 2, (pid:%d)], (pid:%d)\n", rc, (int)getpid());
	printf("back to (pid:%d)\n", (int)getpid());
	rc = fork();
	if( rc == 0 )
		printf("fork() 3, (pid:%d)\n", rc);
	else if( rc > 0 )
		printf("parent of [fork() 3, (pid:%d)], (pid:%d)\n", rc, (int)getpid());
	printf("back to (pid:%d)\n", (int)getpid());
	return 0;
} 

The main function altogether will call fork() 3 times. Each time a fork() system call is invoked, a new process is created, since the child process is almost an exact copy of its parent, the child process will continue to run the code, for example if the child process is created by the first fork(), it will run the code below this call, that is the second and the third fork().

 

references:

https://eli.thegreenplace.net/2018/launching-linux-threads-and-processes-with-clone/

For processes, there's a bit of copying to be done when fork() is invoked, which costs time, due to the lack of CLONE_VM (see https://blog.youkuaiyun.com/MoMo_flamboyant/article/details/83182113).
Linux has an important optimization by using COW (Copy On Write) pages. The child's memory pages are initially mapped to the same pages shared by the parent, and only when we modify them the copy happens. But still, the page tables still have to be copied.
On the other hand, this overhead is not applied the thread, since threads inside a process are sharing address space - using same page tables and mappings.

 

LINE C

CHILD: value = 5

LINE P

PARENT: value = 0

 

For a set of user threads created in a user process, there is a set of corresponding Light Weight Processes(LWPs) in the kernel.

 

test.c

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
struct message {
	int i, j;
}; 
void *hello(struct message *arg)
{
	printf("child thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	printf("%d %d\n", arg->i, arg->j);
	pthread_exit(0);
}
int main(int argc, char *argv[])
{
	printf("main process (pid=%d)\n", (int)getpid());
	printf("main/parent thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	struct message test;
	pthread_t thread_id;
	test.i = 10; test.j = 20;
	pthread_create(&thread_id, NULL, hello(&test), NULL);
	printf("********\n");
	pthread_join(thread_id, NULL);
	printf("********\n");
	return 0;
}

 

test2.c

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
void *runner1(void *param)
{
	printf("child thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	pthread_exit(0);
}
void *runner2(void *param)
{
	printf("child thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	pthread_exit(0);
}
int main()
{
	printf("main process (pid=%d)\n", (int)getpid());
	printf("main thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	pid_t cpid = fork();
	if( cpid == 0 ) {	// child process
		printf("child process (pid=%d)\n", cpid);
		printf("parent thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
		pthread_t tid1;
		pthread_create(&tid1,NULL,runner1,NULL);
		pthread_join(tid1,NULL);
	}
	else if( cpid > 0 ) {	// parent process
		printf("parent process (pid=%d) of process (pid=%d)\n", (int)getpid(), cpid);
		printf("parent thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
		pthread_t tid2;
		pthread_create(&tid2,NULL,runner2,NULL);
		pthread_join(tid2,NULL);
	}
	return 0;
}

 

test3.c

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
void *runner(void *param)
{
	printf("child thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	pthread_exit(0);
}
int main()
{
	printf("main process (pid=%d)\n", (int)getpid());
	printf("main thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
	pid_t pid1 = fork();	//1
	if( pid1 == 0 ) {
		printf("child process (pid1=%d)\n", pid1);
		pid_t pid = fork();	//*
		if( pid == 0 ) {
			printf("child process (pid*=%d)\n", pid);
		}
		else if( pid > 0 ) {
			printf("parent process (pid=%d) of process (pid*=%d)\n", (int)getpid(), pid);
		}
		printf("parent thread: in process (pid=%d), tid = %lu, pid = %ld\n", (int)getpid(), pthread_self(), syscall(SYS_gettid));
		pthread_t tid;
		pthread_create(&tid,NULL,runner,NULL);
		pthread_join(tid,NULL);
	}
	else if( pid1 > 0 ) {
		printf("parent process (pid=%d) of process (pid1=%d)\n", (int)getpid(), pid1);
	}
	pid_t pid2 = fork();	//2
	if( pid2 == 0 ) {
		printf("child process (pid2=%d)\n", pid2);
	}
	else if( pid2 > 0 ) {
		printf("parent process (pid=%d) of process (pid2=%d)\n", (int)getpid(), pid2);
	}
	return 0;
}

6 unique processes are created.

8 unique threads are created.

 

 

注意:

pthread库不是Linux系统默认的库,连接时需要使用静态库libpthread.a,所以在线程函数在编译时,需要连接库函数,
gcc xxx.c -o xxx -lpthread

 

private Watchdog() { 511 mThread = new Thread(this::run, "watchdog"); 512 513 // Initialize handler checkers for each common thread we want to check. Note 514 // that we are not currently checking the background thread, since it can 515 // potentially hold longer running operations with no guarantees about the timeliness 516 // of operations there. 517 // 518 // Use a custom thread to check monitors to avoid lock contention from impacted other 519 // threads. 520 ServiceThread t = new ServiceThread("watchdog.monitor", 521 android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); 522 t.start(); 523 mMonitorChecker = new HandlerChecker(new Handler(t.getLooper()), "monitor thread", mLock); 524 mHandlerCheckers.add(withDefaultTimeout(mMonitorChecker)); 525 526 mHandlerCheckers.add( 527 withDefaultTimeout( 528 new HandlerChecker(FgThread.getHandler(), "foreground thread", mLock))); 529 // Add checker for main thread. We only do a quick check since there 530 // can be UI running on the thread. 531 mHandlerCheckers.add( 532 withDefaultTimeout( 533 new HandlerChecker( 534 new Handler(Looper.getMainLooper()), "main thread", mLock))); 535 // Add checker for shared UI thread. 536 mHandlerCheckers.add( 537 withDefaultTimeout(new HandlerChecker(UiThread.getHandler(), "ui thread", mLock))); 538 // And also check IO thread. 539 mHandlerCheckers.add( 540 withDefaultTimeout(new HandlerChecker(IoThread.getHandler(), "i/o thread", mLock))); 541 // And the display thread. 542 mHandlerCheckers.add( 543 withDefaultTimeout( 544 new HandlerChecker(DisplayThread.getHandler(), "display thread", mLock))); 545 // And the animation thread. 546 mHandlerCheckers.add( 547 withDefaultTimeout( 548 new HandlerChecker( 549 AnimationThread.getHandler(), "animation thread", mLock))); 550 // And the surface animation thread. 551 mHandlerCheckers.add( 552 withDefaultTimeout( 553 new HandlerChecker( 554 SurfaceAnimationThread.getHandler(), 555 "surface animation thread", 556 mLock))); 557 // Initialize monitor for Binder threads. 558 addMonitor(new BinderThreadMonitor()); 559 560 mInterestingJavaPids.add(Process.myPid()); 561 这部分代码中哪些是monitorchecker添加,哪部分是handlerchecker添加
最新发布
07-26
<think>我们正在分析Watchdog的构造函数代码片段。需要区分哪些是添加MonitorChecker,哪些是添加LooperChecker(即HandlerChecker针对不同线程的实例)。 根据之前的讨论: - MonitorChecker 实际上是HandlerChecker的一种,用于检查实现了Watchdog.Monitor接口的服务。 - 在代码中,HandlerChecker有两种使用方式: 1. 用于监控Monitor对象(通过HandlerChecker的post功能,实际在monitor线程中执行monitor()方法) 2. 用于监控线程的Looper(检查消息处理是否超时) 具体到代码片段: 1. 第520-524行:创建了一个专门用于监控的线程(ServiceThread),并基于这个线程的Looper创建了一个HandlerChecker,这个Checker就是用于Monitor的,即mMonitorChecker。 它被添加到mHandlerCheckers列表中(mHandlerCheckers是一个包含所有Checker的列表)。 2. 第526行开始,添加了一系列针对不同系统线程的HandlerChecker(如foreground thread, main thread, ui thread等)。这些Checker都是用来监控对应线程的Looper的消息处理时间的,属于LooperChecker。 3. 第558行:通过addMonitor方法添加了一个BinderThreadMonitor。addMonitor方法内部会将这个Monitor对象添加到mMonitorChecker中(即之前创建的专门用于Monitor的HandlerChecker)。 因此,我们可以总结: - MonitorChecker的添加:在构造函数中,首先创建了一个专门的HandlerChecker(mMonitorChecker)并添加到mHandlerCheckers中。然后通过addMonitor方法添加具体的Monitor实现(如BinderThreadMonitor)到mMonitorChecker中。 - LooperChecker的添加:从第526行到第556行,通过创建多个HandlerChecker(每个绑定到不同线程的Handler)并添加到mHandlerCheckers中,这些就是用于监控各个线程Looper的Checker。 注意:在代码中,所有的Checker都是HandlerChecker类的实例,但根据它们绑定的对象不同(Monitor对象 vs Looper对象)而功能不同。 具体代码对应: - MonitorChecker(即用于Monitor的HandlerChecker)的添加: 520: ServiceThread t = new ServiceThread(...); 522: t.start(); 523: mMonitorChecker = new HandlerChecker(new Handler(t.getLooper()), "monitor thread", mLock); 524: mHandlerCheckers.add(withDefaultTimeout(mMonitorChecker)); - 然后,通过addMonitor方法(第558行)将具体的Monitor实现(BinderThreadMonitor)添加到mMonitorChecker中。 - LooperChecker(即用于监控Looper的HandlerChecker)的添加: 从第526行开始,连续添加了多个HandlerChecker,每个都绑定到一个特定线程的Handler(即该线程的Looper): foreground thread (FgThread) main thread (主线程Looper) ui thread (UiThread) i/o thread (IoThread) display thread (DisplayThread) animation thread (AnimationThread) surface animation thread (SurfaceAnimationThread) 因此,在构造函数中,添加了一个MonitorChecker(用于所有Monitor)和多个LooperChecker(用于各个关键线程)。 注意:在Watchdog中,实际上只有两种HandlerChecker:一种是绑定到Monitor线程(用于执行monitor()方法)的,另一种是绑定到其他线程的Looper(用于检查消息处理时间)的。但它们的基类都是HandlerChecker。 所以,回答: 1. MonitorChecker的添加:通过创建mMonitorChecker(一个HandlerChecker实例,它使用一个专门的monitor线程的Looper)并添加到mHandlerCheckers中,然后通过addMonitor方法将具体的Monitor对象(如BinderThreadMonitor)添加到这个mMonitorChecker中。 2. LooperChecker的添加:通过创建多个HandlerChecker实例,每个实例绑定到一个系统线程的Handler(即Looper),并添加到mHandlerCheckers中。 注意:在代码中,并没有一个单独的类叫MonitorChecker或LooperChecker,它们都是HandlerChecker类,只是初始化时传入的参数不同(一个是专门用于执行monitor的线程的Handler,另一个是各个系统线程的Handler)以及使用方式不同(一个用于执行monitor()方法,一个用于检查消息队列)。 因此,在构造函数中: - 第523行创建的是MonitorChecker(功能上,但类型是HandlerChecker) - 第524行将其添加到总列表 - 第526-556行创建的是多个LooperChecker(同样,功能上,类型也是HandlerChecker)并添加到总列表 最后,第558行通过addMonitor方法将BinderThreadMonitor添加到mMonitorChecker中,这样mMonitorChecker就会在检查时调用BinderThreadMonitor的monitor()方法。 总结添加部分: MonitorChecker(即用于Monitor的HandlerChecker)的初始化:第520-524行(创建并添加到列表),然后第558行添加具体的Monitor对象。 LooperChecker(用于监控线程的HandlerChecker)的初始化:第526-556行(创建多个并添加到列表)。</think>在`Watchdog`构造函数代码中,`MonitorChecker`和`LooperChecker`(即线程监控的HandlerChecker)的添加逻辑如下: ### 一、MonitorChecker 添加部分 1. **专用监控线程创建**(第520-522行) ```java ServiceThread t = new ServiceThread("watchdog.monitor", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); t.start(); ``` 创建名为"watchdog.monitor"的专用服务线程,避免与其他线程锁竞争 2. **MonitorChecker初始化**(第523行) ```java mMonitorChecker = new HandlerChecker(new Handler(t.getLooper()), "monitor thread", mLock); ``` 基于监控线程的Looper创建HandlerChecker实例 3. **添加到检查列表**(第524行) ```java mHandlerCheckers.add(withDefaultTimeout(mMonitorChecker)); ``` 将MonitorChecker加入全局检查队列 ### 二、LooperChecker 添加部分(线程监控) 1. **前台线程监控**(第526-528行) ```java new HandlerChecker(FgThread.getHandler(), "foreground thread", mLock) ``` 2. **主线程监控**(第531-534行) ```java new HandlerChecker(new Handler(Looper.getMainLooper()), "main thread", mLock) ``` 3. **UI线程监控**(第536-537行) ```java new HandlerChecker(UiThread.getHandler(), "ui thread", mLock) ``` 4. **I/O线程监控**(第539-540行) ```java new HandlerChecker(IoThread.getHandler(), "i/o thread", mLock) ``` 5. **显示线程监控**(第542-544行) ```java new HandlerChecker(DisplayThread.getHandler(), "display thread", mLock) ``` 6. **动画线程监控**(第546-549行) ```java new HandlerChecker(AnimationThread.getHandler(), "animation thread", mLock) ``` 7. **Surface动画线程监控**(第551-556行) ```java new HandlerChecker(SurfaceAnimationThread.getHandler(), "surface animation thread", mLock) ``` > 所有LooperChecker都通过`withDefaultTimeout()`包装后加入`mHandlerCheckers`列表 ### 三、特殊监控添加(第558行) ```java addMonitor(new BinderThreadMonitor()); ``` 将Binder线程监控器添加到mMonitorChecker的监控队列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值