POSIX线程库定义了一套用于创建、操纵和管理线程的API。这些API允许程序员在Unix-like系统(如Linux、Solaris)上编写多线程程序
- 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“
pthread_
”打头的- 要使用这些函数库,要通过引入头文件
<pthread.h>
- 链接这些线程函数库时要使用编译器命令的“
-lpthread
”选项
如何查看线程:
指令:
ps -aL
????创建线程
pthread_create:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(*start_routine)(void*), void *arg);
参数说明:
thread
:返回线程IDattr
:设置线程的属性,attr为NULL表示使用默认属性start_routine
:是个函数地址,线程启动后要执行的函数arg
:传递给线程函数的参数,可以是任何类型的数据,但需要通过类型转换与线程函数中的参数类型匹配,也可以传一个类
返回值:成功返回0;失败返回错误码
代码示例:
#include <iostream>
#include <unistd.h>
#include <pthread.h>
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
while(1)
{
cout << "new thread" << ", thread name: " << threadname << endl;
sleep(1);
}
}
int main()
{
pthread_t tid;
ThreadData *td = new ThreadData("thread_1", (uint64_t)time(nullptr), Print);
pthread_create(&tid, nullptr, ThreadRountine, td);
while(1)
{
cout << "I am a main thread" << endl;
sleep(1);
}
return 0;
}
????线程终止
在多线程编程中,线程终止(Thread Termination)是指一个线程结束其执行过程,释放相关资源,并退出其生命周期。线程终止可以是由于线程正常完成其任务,也可以是由于某些异常情况或外部请求导致的提前结束
只终止某个线程而不终止整个进程:
- 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit
- 线程可以调用
pthread_ exit
终止自己- 一个线程可以调用
pthread_ cancel
终止同一进程中的另一个线程
pthread_exit:
代码示例:(运行5秒后退出)
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
// return nullptr;
pthread_exit(nullptr);
}
pthread_cancel:
int pthread_cancel(pthread_t thread);
参数:
thread
:线程ID
代码示例:
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread cancel done" << endl;
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
sleep(5);
// pthread_detach(tid);
int n = pthread_cancel(tid);
cout << "main thread done" << ", n: " << n << endl;
void *ret = nullptr;
n = pthread_join(tid, &ret);
cout << "main thread join done" << " n: " << n << ", thread return: " << (int64_t)ret << endl;
return 0;
}
线程如果是被分离的,该线程可以被取消,但是不能被等待
????线程等待
在Linux或多线程编程环境中,线程等待通常指的是一个线程暂停其执行,直到满足某个特定条件或另一个线程完成某个任务后再继续执行
pthread_join:
int pthread_join(pthread_t thread, void **value_ptr);
参数:
thread
:线程IDvalue_ptr
:它指向一个指针,后者指向线程的返回值
代码示例:
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread done" << endl;
// return nullptr;
pthread_exit(nullptr);
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
sleep(10);
int n = pthread_join(tid, nullptr);
cout << "main thread done" << " n: " << n << endl;
sleep(5);
return 0;
}
如果我们想获取线程的返回值,我们要注意
pthread_join
的第二个参数是void **
类型,而ThreadRoutine
的返回值为void *
,因此我们要对格外注意
获取线程的返回值:
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread done" << endl;
// return nullptr;
return (void *)"thread_1 done";
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
void *ret = nullptr;
int n = pthread_join(tid, &ret); // 注意这里要&ret
cout << "main thread done" << " n: " << n << "thread done and return: "<< (const char*)ret << endl;
return 0;
}
????线程分离
分离线程是多线程编程中的一个重要概念,它指的是将一个线程从主线程或创建它的线程中分离出来,使其能够独立运行,并且不再需要其他线程使用特定的函数(如
pthread_join()
)来等待其结束
pthread_detach:
int pthread_detach(pthread_t thread);
参数:
thread
是你想要分离的线程的标识符(线程ID)
返回值:如果成功,pthread_detach
返回 0。如果失败,它返回一个错误码
代码示例:(在线程分离后等待线程)
// 线程分离
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread done" << endl;
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
sleep(1);
pthread_detach(tid);
int n = pthread_join(tid, nullptr);
cout << "main thread done" << " n: " << n << endl;
return 0;
}
在线程分离后等待线程,线程会直接返回一个错误码
????线程ID
线程ID本质是一个地址
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
while(1)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
cout << "tid: " << tid << endl;
while(1)
{
cout << "I am a main thread" << endl;
sleep(1);
}
return 0;
}
pthread_self:
功能:可以获得线程自身的ID
pthread_t pthread_self(void);
返回值:
pthread_self
函数返回一个类型为pthread_t
的值,这个值唯一地标识了调用它的线程。pthread_t
通常是一个整数或结构体,用于表示线程标识符
代码示例:
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
cout << "pthread_t id: " << pthread_self() << endl;
return 0;
}
线程库要想管理线程,那么它必须要先被加载到地址空间中的mmap区域,线程库是共享的,内部要管理整个系统的,多个用户启动的所有线程
对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址,为了方便我们的库直接找到内存,而pthread_t ID就是pthread的首地址,pthread库要自己维护线程这块栈区
- 线程可以通过函数fork来创建子进程,但是线程不能进行进程程序替换,因为线程是共用主线程的资源,一旦一个线程进行进程程序替换后,所有的线程包括主线程的代码都会被替换为别的程序