Pthread 提供了 Linux / MacOSX 等系统下的一套多线程 API。使用多线程可以用于提升 CPU 利用率, 加速任务执行等。
如果要使用多线程, 但是又不使用 Pthread, 我只能想到如下几种情况:
std::thread
, 坚定的 modern C++, pure C++ 信仰std::thread
实际上 Pthread 在非常多的 操作系统
x 编译器
x 硬件平台
组合条件下可以使用:
使用 Pthread 还有额外的好处:
std::thread
, 大概率也能使用 Pthread,Windows 上有 Windows-Pthreads 库可以使用以上,是我学习使用 Pthread 的主要原因。
使用 ubuntu 22.04。它自带的 man 可以查询 pthread 的 API。
pthread_create()
man pthread_create
PTHREAD_CREATE(3) Linux Programmer's Manual PTHREAD_CREATE(3)
NAME
pthread_create - create a new thread
SYNOPSIS
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.
pthread_join()
这个API用于在当前线程等待子线程的结束。
PTHREAD_JOIN(3) Linux Programmer's Manual PTHREAD_JOIN(3)
NAME
pthread_join - join with a terminated thread
SYNOPSIS
#include
int pthread_join(pthread_t thread, void **retval);
Compile and link with -pthread.
何为最简单?能省则省, 能用默认就用默认。换言之使用最小必要条件创建一个子线程。
要点:
f
(命名就很简洁)f
需要返回 void*
类型f
需要传入 void*
类型参数pthread_create()
函数pthread_join()
函数按如上要点很容易写出如下实现:
simplest.cpp
//
// 最简单的 pthread 创建线程的例子: 创建一个线程。线程参数和线程属性都用NULL
//
#include
#include
// 1. 线程函数返回值, 必须是 void*
// 2. 线程函数参数, 必须只有一个, 类型必须是 void*
void* f(void*)
{
printf("This is thread function\n");
return NULL;
}
int main()
{
pthread_t t; // 3. 创建线程对象变量
pthread_create(&t, NULL, f, NULL); // 4. 创建线程: 传入线程对象(参数1), 传入线程函数(参数3)。
pthread_join(t, NULL); // 等待线程结束
return 0;
}
编译并运行:
zz@Legion-R7000P% clang++ simplest.cpp
zz@Legion-R7000P% ./a.out
This is thread function
可以看到, 函数 f
被执行, 而 f
并不是按常规的 f()
方式显式调用,而是一种回调(callback)方式调用的。
基于前一节的代码,这次创建4个线程。创建线程、等待子线程结束的两段代码,各自用 for 循环包裹起来即可实现。
multiple_threads.cpp
:
//
// 创建多个线程。线程属性和线程参数仍然用NULL。
//
#include
#include
void* hello(void*)
{
printf("This is hello\n");
return NULL;
}
int main()
{
const int N = 4;
pthread_t t[N];
for (int i = 0; i < N; i++)
{
pthread_create(&t[i], NULL, hello, NULL);
}
for (int i = 0; i < N; i++)
{
pthread_join(t[i], NULL);
}
return 0;
}
编译并运行:
zz@Legion-R7000P% clang++ multiple_threads.cpp
zz@Legion-R7000P% ./a.out
This is hello
This is hello
This is hello
This is hello
可以看到, 输出了4句相同的 This is hello
, 说明确实运行了4次 f
函数, 而且主线程并没有显式调用 f()
, 而是一种回调方式, 通过子线程来实现的调用。
这里的例子很简单, 说是简陋也不为过: