C++线程详解
1.Linux线程的概念
我们在写C/C++程序的时候,都是重main函数开始执行的,从上而下,只有一条执行路线。如果我们想要同时干两件事或者多件事,这次我们就需要线程,分出一个执行分支来执行任务。
•在一个程序里的一个执行路线叫做线程
•线程在进程内部运⾏,本质是在进程地址空间内运行
•有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的工作, 也需要用到并发编程。其次,虽然多进程也能实现 并发编程, 但是线程比进程更轻量.
2.创建线程
在Linux上,没有提供专门的线程,而是提供了轻量化进程,为了满足用户的遍历,在语言层实现了封装,在pthread的库中提供了专门的调用接口。
2-1 认识pthread_create函数
#include <pthread.h>int pthread_create(pthread_t *thread, // 指向线程标识符的指针const pthread_attr_t *attr, // 线程属性(通常设为 NULL 使用默认属性)void *(*start_routine)(void*), // 线程执行的函数void *arg // 传递给线程函数的参数
);
参数说明
thread
指向pthread_t
类型的变量,用于存储新创建线程的标识符。attr
指向pthread_attr_t
类型的结构体,用于设置线程的属性(如栈大小、调度策略等)。若为NULL
,则使用默认属性。start_routine
线程启动后要执行的函数,必须符合void* (*)(void*)
的函数签名,即接受一个void*
类型的参数并返回void*
。arg
传递给start_routine
的参数,类型为void*
。若无需传递参数,可设为NULL
。
返回值
- 成功:返回
0
。 - 失败:返回错误码(如
EAGAIN
、EINVAL
等),且*thread
的值未定义。
2-2 案例实现
//新线程执行流
void* threadrun(void* args)
{//这里的args拿到的就是创建线程时传递的地址,类型是无符号类型,在使用时需要自己进行强转std::string name = (const char*)args;while(1){std::cout << "我是新线程:name" << name << std::endl;sleep(1);}return nullptr;
}//main执行流
int main()
{pthread_t tid;//调用接口创建线程pthread_create(&tid, nullptr, threadrun, (void*)"thread -1");while(1){std::cout << "我是主线程..." << std::endl;sleep(1);}return 0;}//运行结果
我是主线程...
我是新线程:namethread -1
我是主线程...
我是新线程:namethread -1
我是主线程...
我是新线程:namethread -1
我是主线程...
我是新线程:namethread -1
可以看到上述有两个while死循环,分别属于两个执行流,同时进行输出。
3.线程等待
主线程也就是main执行流有时需要等待新线程完成相应的任务,并回收新线程的资源。这个时候就需要线程等待(类似于进程等待)
3-1 线程等待函数
#include <pthread.h>int pthread_join(pthread_t thread, void **retval);
- 功能:阻塞当前线程,直到指定的
thread
线程终止。 - 参数:
thread
:目标线程的标识符(由pthread_create()
返回)。retval
:指向void*
的指针,用于存储线程函数的返回值(即start_routine
的返回值)。若无需获取返回值,可设为NULL
。
- 返回值:
- 成功:返回
0
。 - 失败:返回错误码(如
EDEADLK
、ESRCH
等)。
- 成功:返回
3-2 实现案例
void* routine(void* args)
{std::string name = (char*)args;int cut = 5;while(cut--){sleep(1);std::cout << "我是一个线程" << Formata(pthread_self()) << cut << std::endl;}static int a = 10;return (void*)(&a);
}//实现一个线程等待的案例
int main()
{pthread_t tid;int n = pthread_create(&tid, nullptr, routine, (void*)"thread -1");void* a = nullptr;pthread_join(tid,&a);std::cout << *(int*)a << std::endl;}
这里的新线程在内部创建了一个静态变量a,并返回了a的地址。主线程(main)进行线程等待,回收新线程。拿到返回值a的地址。
4. 线程分离
在新线程结束的时候,我们需要等待主线程回收新线程,如果我们不想等待新线程,我们可以把新线程分离出来,这样在其终止后,资源会自动释放,无需其他线程等待。
4-1线程分离函数
#include <pthread.h>int pthread_detach(pthread_t thread);
- 功能:将线程标记为 “分离” 状态,使其终止后资源自动释放,无需其他线程调用
pthread_join()
。 - 参数:
thread
:目标线程的标识符。
- 返回值:
- 成功:返回
0
。 - 失败:返回错误码(如
ESRCH
)。
- 成功:返回
4-2 实现案例
主线程和新线程都可以设置线程分离
void* thread(void* args)
{// pthread_detach(pthread_self());sleep(10);}int main()
{pthread_t tid;pthread_create(&tid, nullptr, thread, (void*)"threadtest");pthread_detach(tid);while(1){std::cout << "我是主线程" << std::endl;}
}
5.线程退出
#include <pthread.h>
void pthread_exit(void *retval);
- 功能:立即终止当前线程,并通过
retval
传递返回值。