B站缓存视频转换终极指南:3分钟学会m4s转MP4永久保存
2026/7/15 14:05:20
| 特征 | 说明 |
|---|---|
| 资源分配 | 进程是系统最小资源分配单位,线程不单独分配资源(共享进程资源) |
| 执行单位 | 线程是系统最小执行单位,CPU调度的基本对象 |
| 层级关系 | 进程内线程平级,默认存在一个“主线程”(main函数所在线程) |
| 资源共享 | 线程间共享进程的全局变量、静态变量、文件描述符等,仅栈区(8MB)独立 |
| 稳定性 | 线程不稳定:一个线程崩溃会导致整个进程退出;进程相对稳定,互不影响 |
| 创建开销 | 线程创建仅需开辟独立栈区(8MB),进程创建需分配3GB虚拟地址空间,开销更大 |
| 并发度 | 线程并发度高于进程,同一进程内线程切换无需切换地址空间,效率更高 |
| 对比维度 | 线程(Thread) | 进程(Process) |
|---|---|---|
| 资源分配 | 共享所属进程资源,无独立地址空间 | 独立地址空间,资源独立(代码段、数据段等) |
| 创建/切换开销 | 小(仅开辟栈区) | 大(分配完整地址空间) |
| 通信方式 | 直接访问共享变量,通信简单 | 需通过IPC(管道、消息队列等),通信复杂 |
| 稳定性 | 低(线程崩溃导致进程退出) | 高(进程间相互隔离) |
| 并发效率 | 高(线程切换无需地址空间切换) | 低(进程切换开销大) |
pthread_create创建子线程,指定线程执行函数;pthread_join(阻塞回收)或pthread_detach(自动回收)释放线程资源,避免内存泄漏。POSIX线程函数库(libpthread)提供了线程操作的核心接口,以下是常用函数说明:
| 函数原型 | 功能描述 |
|---|---|
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) | 创建子线程 - thread:输出参数,存储新线程ID- attr:线程属性(默认NULL)- start_routine:线程回调函数(执行入口)- arg:回调函数参数- 返回值:成功0,失败返回错误码 |
pthread_t pthread_self(void) | 获取当前线程ID - 返回值:当前线程的ID( unsigned long类型,打印用%lu) |
void pthread_exit(void *retval) | 子线程主动退出 - retval:线程退出状态(返回给主线程) |
int pthread_cancel(pthread_t thread) | 主线程取消指定子线程 - thread:目标线程ID- 返回值:成功0,失败返回错误码 |
int pthread_join(pthread_t thread, void **retval) | 阻塞回收子线程资源 - thread:待回收线程ID- retval:接收子线程退出状态- 返回值:成功0,失败返回错误码 |
int pthread_detach(pthread_t thread) | 设置线程分离属性(退出后自动回收资源) - 无需主线程调用 pthread_join |
# 查看系统所有线程(PID:进程ID,LWP:线程ID,COMM:线程名称)ps-eLo pid,ppid,lwp,stat,comm# 查看线程详细信息(含CPU占用、内存等)ps-eLf以下结合8个实战代码,从基础到进阶,逐步掌握线程编程技巧(所有代码需链接pthread库编译:gcc 文件名.c -o 文件名 -lpthread)。
#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<string.h>// 线程1回调函数:发视频void*thread_function(void*arg){while(1){printf("发视频...\n");sleep(1);// 每隔1秒执行一次}returnNULL;}// 线程2回调函数:接收控制void*thread_function2(void*arg){while(1){printf("接受控制...\n");sleep(1);}returnNULL;}intmain(){pthread_tthread_id;// 线程1 IDpthread_tthread_id2;// 线程2 ID// 创建线程1pthread_create(&thread_id,NULL,thread_function,NULL);// 创建线程2pthread_create(&thread_id2,NULL,thread_function2,NULL);// 主线程阻塞(避免主线程退出导致子线程终止)while(1){sleep(1);}return0;}pthread_create参数:线程ID指针、默认属性(NULL)、回调函数、回调函数参数(NULL);while(1)),否则主线程退出后,整个进程终止,子线程也会被销毁;gcc 01pthread.c -o 01pthread -lpthread;pthread_self()获取主线程和子线程的ID#include<stdio.h>#include<pthread.h>#include<unistd.h>#include<stdlib.h>#include<string.h>void*th1(void*arg){while(1){// 打印子线程1 ID(%lu对应unsigned long类型)printf("发视频...tid:%lu\n",pthread_self());sleep(1);}returnNULL;}void*th2(void*arg){while(1){printf("接受控制...tid:%lu\n",pthread_self());sleep(1);}returnNULL;}intmain(){pthread_ttid1,tid2;pthread_create(&tid1,NULL,th1,NULL);pthread_create(&tid2,NULL,th2,NULL);// 打印主线程IDwhile(1){printf("main tid:%lu\n",pthread_self());sleep(1);}return0;}pthread_self()无参数,返回当前线程的ID(类型为pthread_t,建议用%lu格式化输出);ps -eLo lwp,comm验证线程是否存在。pthread_exit()主动退出,主线程运行指定次数后退出#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<string.h>void*th(void*arg){while(1){printf("sub_th %lu\n",pthread_self());sleep(1);}pthread_exit(NULL);// 子线程主动退出(此处因while(1)无法执行到,仅作演示)}intmain(){pthread_ttid;pthread_create(&tid,NULL,th,NULL);inti=8;// 主线程运行8秒后退出while(i--){printf("main_th %lu\n",pthread_self());sleep(1);}return0;}pthread_exit(NULL):子线程主动退出,参数为退出状态(NULL表示无返回值);while(1));pthread_cancel()取消子线程#include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<unistd.h>#include<string.h>void*thread_func(void*arg){while(1){printf("subth %lu\n",pthread_self());sleep(1);}}intmain(){pthread_ttid;pthread_create(&tid,NULL,thread_func,NULL);inti=0;while(1){printf("main th %lu\n",pthread_self());sleep(1);i++;if(i==2){// 运行2秒后,主线程取消子线程pthread_cancel(tid);printf("子线程已取消\n");}}return0;}pthread_cancel(tid):向指定子线程发送取消请求,子线程在“取消点”(如sleep、printf等系统调用)响应;pthread_cancel仅发送请求,若子线程无取消点(如纯计算循环),需手动调用pthread_testcancel()设置取消点。pthread_join()阻塞等待子线程完成,回收资源#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<pthread.h>void*th(void*arg){inti=5;while(i--){printf("workth,%lu\n",pthread_self());sleep(1);}returnNULL;}intmain(intargc,char**argv){pthread_ttid;pthread_create(&tid,NULL,th,NULL);// 阻塞等待子线程tid完成,回收其资源pthread_join(tid,NULL);printf("子线程已结束,主线程退出\n");return0;}pthread_join(tid, NULL):主线程阻塞,直到子线程tid退出,避免子线程成为“僵尸线程”(资源未回收);NULL,表示不关心子线程的退出状态;pthread_join()获取返回值并释放内存#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>#include<unistd.h>void*th(void*arg){// 动态分配内存(子线程栈区数据不能返回,会随线程退出释放)char*str=(char*)malloc(20);strcpy(str,"我要灭亡了");returnstr;// 返回动态内存地址}intmain(intargc,char*argv[]){pthread_ttid;pthread_create(&tid,NULL,th,NULL);void*ret=NULL;// 回收子线程,获取返回值(ret指向子线程分配的内存)pthread_join(tid,&ret);printf("子线程返回值:%s\n",(char*)ret);free(ret);// 释放子线程分配的内存,避免内存泄漏return0;}malloc动态分配内存;pthread_join的第二个参数&ret接收返回值,使用后需手动free;#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<string.h>// 定义结构体(存储用户信息)typedefstruct{charname[20];intage;charaddress[50];}PER;void*th(void*arg){// 将void*类型转换为结构体指针PER*p=(PER*)arg;printf("子线程接收的信息:\n");printf("name:%s\n",p->name);printf("age:%d\n",p->age);printf("address:%s\n",p->address);