Linux POSIX 多线程
一、多线程介绍
- 单线程:程序是一条单行道。一旦阻塞,全盘挂起。不能并发处理其他任务(网络监听、数据读取)。
- 多线程:允许程序同时执行多个任务
- 主线程(main):负责板卡初始化、配置文件解析,维持程序常驻保护,响应退出信号
- 后台工作线程:独立运行在后台(UDP 监听指令、板卡数据采集、DDS网络推送…)
二、POSIX 线程函数规范
在 Linux 中,交给pthread_create执行的线程入口函数要遵循下面格式:
void*thread_func_name(void*pParam);参数
void* pParam:void*是 C/C++ 中的 万能指针。操作系统创建线程时不知道具体业务传递什么数据(整数、结构体、指针),因此按void*传递。- 进入线程后,再将 pParam 强转为具体数据类型。
返回值
void*:- 线程正常结束时若无特殊数据返回,直接
return NULL即可。
- 线程正常结束时若无特殊数据返回,直接
三、线程生命周期四步
1.创建线程
通知操作系统创建一个新的子线程去跑函数。
#include <pthread.h> /* pthread_t 是 Linux POSIX 线程库中用来标识线程 ID 的数据类型 */ pthread_t tid; // 线程 ID // 创建线程并启动 pthread_create(&tid, NULL, thread_func_name, (void*)&serverSock);&tid:传入pthread_t变量地址,用于接收系统分配的线程 ID。NULL:线程属性,NULL默认属性thread_func_name:线程入口函数名(指针)。(void*)&serverSock:传给子线程函数的参数指针,若无参数可传NULL。
2.编写线程入口函数
线程一旦被创建,会自动进入这个函数执行,一般内部会带有while循环做常驻任务:
// 示例:数据接收线程 void* thread_func_name(void* pParam) { // 1. 将万能指针强转为实际类型 int serverSock = *(int*)pParam; // 2.线程主循环(标志位为真,就继续执行任务) while (g_running) { // 执行具体网络接收或业务处理 // recv(...); usleep(1000); // 休眠 1ms,防止CPU占用率100% } //3.退出线程 return NULL; }3.回收线程
主线程退出或关闭服务时,需要等待后台子线程安全退出,防止子线程还在跑程序就把内存释放了:
// 1.先通过标志位通知子线程退出循环 g_running = 0; // 2.主线程阻塞等待子线程真正执行完毕并回收资源 pthread_join(tid, NULL);tid:要等待的子线程 ID。NULL:用于接收子线程return的指针,不需要时传NULL。
4.线程同步/锁
如果有多个线程同时读写同一个变量(例如一个线程写数据,另一个线程读数据),为了防止数据错乱,需要加锁:
// 1.定义并初始化互斥锁 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 2.上锁 pthread_mutex_lock(&lock); // 3.临界区代码(安全地读写共享数据) /* ...... */ // 4.解锁 pthread_mutex_unlock(&lock);