一、进程管理进阶

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。
危害:占用内核进程表项,若大量僵尸进程会导致无法创建新进程。

避免僵尸进程的方法

  1. 父进程主动回收:调用waitwaitpid

  2. 让父进程先结束:子进程成为孤儿进程,被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
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐