一、核心结论
Linux 线程控制依赖 POSIX 线程库(pthread 库),核心操作包括创建、终止、等待、分离。线程创建通过pthread_create实现,终止有三种合法方式(return、pthread_exit、pthread_cancel),需避免使用exit(终止整个进程)。
二、POSIX 线程库(pthread 库)基础
使用 pthread 库的核心注意事项:
- 头文件:
#include <pthread.h>; - 编译链接:必须添加
-lpthread参数(告知编译器链接线程库); - 错误处理:pthread 函数不设置全局
errno,错误码通过返回值返回,可通过strerror(ret)打印错误信息; - 线程 ID:
pthread_t类型,Linux 下本质是虚拟地址空间中的地址,进程内唯一。
三、线程创建:pthread_create 函数详解
1. 函数原型
int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg);
2. 参数说明
| 参数名 | 作用 |
|---|---|
| tidp | 输出参数,存储新线程的 ID(用户态标识) |
| attr | 线程属性(如栈大小、调度优先级),NULL 表示使用默认属性 |
| start_routine | 线程执行函数指针,原型为void* (*)(void*),参数和返回值均为void* |
| arg | 传递给线程执行函数的参数,需强制类型转换为void* |
3. 返回值
- 成功:返回 0;
- 失败:返回非 0 错误码(如 EAGAIN:资源不足,EPERM:无权限设置线程属性)。
4. 代码示例:创建简单线程
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
// 线程执行函数
void* thread_routine(void* arg) {
char* thread_name = (char*)arg;
printf("线程%s启动,线程ID:%lu\n", thread_name, (unsigned long)pthread_self());
sleep(2); // 模拟任务执行
printf("线程%s执行完毕\n", thread_name);
return (void*)100; // 线程返回值,后续可通过pthread_join获取
}
int main() {
pthread_t tid;
int ret;
// 创建线程:默认属性,传递参数"线程1"
ret = pthread_create(&tid, NULL, thread_routine, (void*)"线程1");
if (ret != 0) {
printf("创建线程失败:%s\n", strerror(ret));
return -1;
}
printf("主线程ID:%lu,创建的线程ID:%lu\n", (unsigned long)pthread_self(), (unsigned long)tid);
// 等待线程结束(后续章节详解)
void* exit_status;
ret = pthread_join(tid, &exit_status);
if (ret != 0) {
printf("等待线程失败:%s\n", strerror(ret));
return -1;
}
printf("线程退出状态:%d\n", (int)exit_status);
return 0;
}
5. 编译与运行
gcc -o thread_create thread_create.c -lpthread
./thread_create
6. 运行结果
主线程ID:140709324857152,创建的线程ID:140709316464384
线程1启动,线程ID:140709316464384
线程1执行完毕
线程退出状态:100
关键注意点:
- 传递给线程的参数需是有效地址(全局变量、堆内存或数组),避免传递局部变量(主线程退出后地址失效);
pthread_self()获取的是用户态线程 ID,内核线程 ID 需通过syscall(SYS_gettid)获取(需包含<sys/syscall.h>)
下面再补一份代码
cpp
#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
class task
{
public:
task(int a, int b)
: _a(a)
, _b(b)
{}
~task()
{}
int Add()
{
return _a + _b;
}
private:
int _a;
int _b;
};
class result
{
public:
result(int result)
: _result(result)
{}
~result()
{}
int GetResult()
{
return _result;
}
private:
int _result;
};
/*
void* routine(void* args)
{
task* t = (task*)args;
sleep(100);
result* r = new result(t->Add());
sleep(1);
//return (void*)r;
pthread_exit(r); //结束新线程
std::cout << "新线程不应该看到这里" << std::endl;
}
*/
void* routine(void* args)
{
std::string name = (const char*)args;
int cnt = 5;
while (cnt--)
{
std::cout << "我是new线程, 我的name : " << name << " , cnt : " << cnt << std::endl;
sleep(1);
}
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, routine, (void*)"pthread -> 1");
pthread_detach(tid);
std::cout << "main线程将new线程分离" << std::endl;
int cnt = 3;
while (cnt--)
{
std::cout << "我是main线程" << std::endl;
sleep(1);
}
int n = pthread_join(tid, nullptr);
if (n == 0)
{
std::cout << "stay success" << std::endl;
}
else
{
std::cout << "stay error : " << strerror(n) << std::endl;
}
return 0;
}
/*
int main()
{
pthread_t tid;
task* t = new task(1, 2);
pthread_create(&tid, nullptr, routine, t);
void* ret = nullptr;
sleep(1);
std::cout << "主线程将新线程终止" << std::endl;
sleep(1);
pthread_cancel(tid);
pthread_join(tid, &ret);
//std::cout << ((result*)ret)->GetResult() << std::endl;
std::cout << "新线程终止返回值 : " << (long long)ret << std::endl;
delete t;
//delete (result*)ret;
return 0;
}
*/