Linux软件编程: 进程管理进阶以及线程管理
/ 使用PATH搜索。// 不会输出"Hello"// 会输出"Hello":进程退出状态,通常0表示正常,非0表示异常。:占用内核进程表项,若大量僵尸进程会导致无法创建新进程。:阻塞等待指定线程结束,并回收其资源,获取退出状态。:结束当前线程,可返回一个指针(指向退出状态)。:可指定等待某个子进程,并可设置为非阻塞模式。:成功不返回,失败返回-1并设置errno。:成功返回0,失败返回错误码(非
一、进程管理进阶
1. 进程退出函数:exit 与 _exit
| 函数 | 原型 | 特点 |
|---|---|---|
exit |
void exit(int status); |
刷新I/O缓冲区,执行退出处理函数(atexit注册),最后进入内核 |
_exit |
void _exit(int status); |
直接进入内核,不刷新缓冲区,不执行退出处理函数 |
区别示例:
c
printf("Hello"); // 无换行符
exit(0); // 会输出"Hello"
_exit(0); // 不会输出"Hello"
status:进程退出状态,通常0表示正常,非0表示异常。父进程可通过wait相关宏获取该状态。
2. 等待子进程:wait & waitpid
(1) wait
c
pid_t wait(int *wstatus);
-
功能:阻塞等待任意一个子进程结束,回收其资源。
-
参数:
wstatus存放子进程退出状态信息。 -
返回值:成功返回子进程PID,失败返回-1。
(2) waitpid
c
pid_t waitpid(pid_t pid, int *wstatus, int options);
-
功能:可指定等待某个子进程,并可设置为非阻塞模式。
-
参数:
-
pid:>0表示指定子进程PID;=-1表示任意子进程(同wait)。 -
options:0表示阻塞;WNOHANG表示非阻塞,若无子进程结束立即返回0。
-
-
返回值:成功返回子进程PID,若
WNOHANG且无子进程退出返回0,失败返回-1。
状态宏(用于解析wstatus)
| 宏 | 说明 |
|---|---|
WIFEXITED(status) |
是否正常退出(调用exit或return) |
WEXITSTATUS(status) |
获取正常退出时的返回值(低8位) |
WIFSIGNALED(status) |
是否被信号杀死 |
WTERMSIG(status) |
获取杀死进程的信号编号 |
WCOREDUMP(status) |
是否产生core dump |
WIFSTOPPED(status) |
进程是否暂停 |
WSTOPSIG(status) |
获取导致暂停的信号编号 |
WIFCONTINUED(status) |
进程是否恢复运行(Linux 2.6.10+) |
3. 进程的消亡与僵尸进程
僵尸进程:子进程结束,但父进程未调用wait回收,子进程PCB仍保留,状态为Z。
危害:占用内核进程表项,若大量僵尸进程会导致无法创建新进程。
避免僵尸进程的方法:
-
父进程主动回收:调用
wait或waitpid。 -
让父进程先结束:子进程成为孤儿进程,被
init(PID=1)收养,init会在子进程结束时自动回收。
示例:
c
if (fork() == 0) {
// 子进程
exit(0);
} else {
// 父进程
wait(NULL); // 回收子进程
}
4. exec函数族
作用:在调用进程空间中执行另一个程序,不创建新进程,新程序替换原进程的代码段、数据段、堆栈,PID保持不变。
常用函数:
c
int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const char *path, const char *arg, ... /*, char *const envp[] */); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[], char *const envp[]);
命名规律:
-
l(list):参数以列表形式传入,以NULL结尾。
-
v(vector):参数以字符串数组形式传入。
-
p(path):在环境变量
PATH指定的目录下搜索程序文件。 -
e(environment):可自定义环境变量数组。
示例:
c
// 执行 ls -l
execl("/bin/ls", "ls", "-l", NULL);
execlp("ls", "ls", "-l", NULL); // 使用PATH搜索
char *argv[] = {"ls", "-l", NULL};
execv("/bin/ls", argv);
返回值:成功不返回,失败返回-1并设置errno。
二、线程基础
1. 进程 vs 线程
| 维度 | 进程 | 线程 |
|---|---|---|
| 资源分配 | 独立地址空间 | 共享进程地址空间(代码、数据、堆) |
| 调度单位 | 传统上是进程,现Linux线程也是调度单位 | 轻量级,CPU调度基本单位 |
| 栈 | 独立栈 | 每个线程独立栈(默认8M) |
| 创建开销 | 大(复制页表等) | 小(共享大部分资源) |
| 通信 | IPC(管道、共享内存、消息队列) | 直接读写全局变量(需同步) |
线程优点:创建快、切换快、通信简单、充分利用多核。
2. 线程创建
c
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
-
thread:传出参数,存储新线程ID。
-
attr:线程属性,NULL表示默认属性。
-
start_routine:线程入口函数,参数为
void*,返回值为void*。 -
arg:传递给线程函数的参数。
-
返回值:成功返回0,失败返回错误码(非-1)。
注意:编译时需加-pthread链接线程库。
示例:
c
void* thread_func(void* arg) {
printf("Thread: %d\n", *(int*)arg);
return NULL;
}
int main() {
pthread_t tid;
int val = 123;
pthread_create(&tid, NULL, thread_func, &val);
pthread_join(tid, NULL); // 等待线程结束
return 0;
}
3. 线程退出
c
void pthread_exit(void *retval);
-
功能:结束当前线程,可返回一个指针(指向退出状态)。
-
若主线程调用
pthread_exit,进程不会结束,直到所有线程结束。 -
线程函数中
return等价于pthread_exit(返回值即retval)。
4. 线程等待
c
int pthread_join(pthread_t thread, void **retval);
-
功能:阻塞等待指定线程结束,并回收其资源,获取退出状态。
-
参数:
retval为二级指针,接收线程退出的返回值。 -
返回值:成功返回0,失败返回错误码。
类似进程的waitpid,线程资源必须回收,否则产生僵尸线程。
5. 补充:其他常用线程函数
| 函数 | 功能 |
|---|---|
pthread_t pthread_self(void); |
获取当前线程ID |
int pthread_equal(pthread_t t1, pthread_t t2); |
比较两个线程ID是否相等 |
int pthread_detach(pthread_t thread); |
将线程设为分离态,结束自动回收资源,不可join |
更多推荐


所有评论(0)