1084 字
5 分钟

多线程入门:用C语言轻松实现并发任务

2024-02-20
浏览量 加载中...

一、故事开场:一个人 vs 三个人#

想象你在家里:

  • 一个人版本:先看电视,看完一集再去玩游戏,玩累了再听音乐——三件事串行,总耗时 = 看 + 玩 + 听。
  • 三个人版本:你、朋友 A、朋友 B 同时开工——并行推进,总耗时 ≈ 最长的一项。

计算机里的“线程”就是这位“朋友”。一个进程(你家)可以招很多线程(朋友)一起干活,共享客厅(内存),但各自带自己的记事本(栈)。

二、线程是什么?一句话记住#

线程 = 轻量级的“子任务”,共享地址空间,切换成本比进程低得多。

三、Linux 下的“招工”神器:pthread#

POSIX 线程(pthread)是 Linux/Unix 系统自带的线程库,用法简单,三步走:

  1. 写线程函数 → 2. 创建线程 → 3. 回收线程

四、最小可运行示例:让三条任务一起跑#

下面这段代码同时启动三条“死循环”任务,每秒打印一次状态。先睹为快,再逐行拆解。

// 编译:gcc mini_thread.c -o mini_thread -pthread
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* watch_tv(void* arg) {
while (1) {
printf("[看电视] 剧情太精彩啦!\n");
sleep(1);
}
return NULL;
}
void* play_game(void* arg) {
while (1) {
printf(" [玩游戏] 五连绝世!\n");
sleep(1);
}
return NULL;
}
void* listen_music(void* arg) {
while (1) {
printf(" [听音乐] 动次打次!\n");
sleep(1);
}
return NULL;
}
int main() {
pthread_t t1, t2, t3;
pthread_create(&t1, NULL, watch_tv, NULL);
pthread_create(&t2, NULL, play_game, NULL);
pthread_create(&t3, NULL, listen_music, NULL);
while (1) { // 主线程也陪跑
printf("[主线程] 我还活着\n");
sleep(1);
}
return 0;
}

运行效果(节选,实际交错):

[看电视] 剧情太精彩啦!
[主线程] 我还活着
[玩游戏] 五连绝世!
[听音乐] 动次打次!
...

五、逐行拆解,10 分钟看懂#

代码片段作用
pthread_t t1;定义线程“工牌”变量
pthread_create(&t1, NULL, 函数, 参数)招工:把函数变成线程
void* 函数(void* arg)线程入口,必须这个签名
sleep(1);让出 CPU,避免刷屏
while(1)演示用死循环,实际项目会放退出条件

六、改进版:让线程“下班”#

死循环演示可以,生产环境必须可控退出 + 资源回收。思路:

  1. 全局放一面“停工序牌”:volatile int g_stop = 0;
  2. 线程循环检测:while (!g_stop) { ... }
  3. 主线程下班后挂牌:g_stop = 1;
  4. 等待所有人收工:pthread_join

完整代码:

// gcc better_thread.c -o better_thread -pthread
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
volatile int g_stop = 0; // ① 停工标志
typedef struct { // ② 打包参数
const char* name;
int gap;
} Task;
void* worker(void* arg) {
Task* t = (Task*)arg;
while (!g_stop) {
printf("[%s] 工作中...\n", t->name);
sleep(t->gap);
}
printf("[%s] 收到停工通知,拜拜!\n", t->name);
return NULL;
}
int main() {
pthread_t t[3];
Task tasks[3] = {
{"看电视", 1},
{"玩游戏", 2},
{"听音乐", 3}
};
for (int i = 0; i < 3; ++i)
pthread_create(&t[i], NULL, worker, &tasks[i]);
sleep(8); // 让任务跑 8 秒
g_stop = 1; // ③ 挂牌停工
for (int i = 0; i < 3; ++i)
pthread_join(t[i], NULL); // ④ 收工清点
puts("主线程:所有人都下班了,关灯!");
return 0;
}

运行 8 秒后,你会看到三条线程有序退出,资源干净回收。

七、常见坑位排雷#

现象避坑指南
忘记 -pthread编译报错“未定义引用”永远带 -pthread:既链接库又开宏
主线程直接 return子线程被强制“团灭”pthread_joinpthread_detach 收尾
printf 交错输出乱序正常现象,加锁或整行缓冲可缓解
传参用局部变量线程拿到野指针传堆内存或全局/静态变量
死循环无退出程序关不掉设退出标志或外部信号

八、下一步学什么#

  1. 同步原语:互斥锁 pthread_mutex_t、条件变量 pthread_cond_t
  2. 经典模型:生产者-消费者、读者-写者
  3. 线程池:统一管理任务,避免频繁创建销毁
  4. C11 <threads.h> 与 C++ std::thread:跨平台新接口

九、一分钟总结#

  • 线程 = 共享内存的多任务,切换快。
  • pthread 三板斧:create 创建 → join/detach 回收 → 同步原语保安全。
  • 写线程函数注意签名 void* (*)(void*),传参注意生命周期。
  • 永远加 -pthread,永远考虑退出策略。

把示例粘进终端,亲手编译运行一次,你就已经踏进“并发”的大门啦!祝你玩得开心,bug 少少。

多线程入门:用C语言轻松实现并发任务
https://demo-firefly.netlify.app/posts/c-language-multithreading-introduction/
作者
长琴
发布于
2024-02-20
许可协议
CC BY-NC-SA 4.0
最后更新于 2024-02-20,距今已过 640 天

部分内容可能已过时

评论区

目录

Loading ... - Loading ...
封面
Loading ...
Loading ...
0:00 / 0:00