技术支持 滕州网站建设,无锡专业网站建设,北京最新进出京政策,外贸网站建设如何做呢一、编译环境准备 在正式进入c/c多线程编程系列之前#xff0c;先来搭建支持多线程编译的编译环境。 1.1 MinGW#xff08;win#xff09; 进入Downloads - MinGW-w64下载页面#xff0c;选择MinGW-w64-builds跳转下载#xff0c; 再次进行跳转#xff1a; 然后进入下载页…一、编译环境准备 在正式进入c/c多线程编程系列之前先来搭建支持多线程编译的编译环境。 1.1 MinGWwin 进入Downloads - MinGW-w64下载页面选择MinGW-w64-builds跳转下载 再次进行跳转 然后进入下载页面WinLibs - GCCMinGW-w64 compiler for Windows下拉到Download标题下面按需下载本文选择的是编译好的WIN工具包 本文下载的如下 将该工具包解压到无汉字、特殊字符的路径上例如本文 进入环境变量配置页面在path环境变量中添加mingw路径 运行命令工具测试gcc -v和g -v是否生效例如下图 1.2 Cygwin(win) 同样还是Downloads - MinGW-w64下载页面选择Cygwin选项跳转 选择setup.exe安装工具包跳转 进入Cygwin Installation页面下载 下载完成后得到直接安装的.exe文件 双击安装按安装说明引导路径设置最好不包含汉字和特殊符号本文安装如下 安装完成后同样可以去配置环境变量本文是先设置了变量在引入path环境变量中的。 如果没有创建Cygwin的桌面快捷方式 可以自行进入路径手动创建该快捷方式。 双击快捷方式启动进入一个仿linux系统运行的win编译工具命令窗口通过gcc -v或g -v测试是否支持c/c编译. 那么windows的磁盘文件就在/cygdrive目录下 另外可以右键窗口选择options项进入窗口设置例如窗口大小、字体等保存后重启生效。 1.3、纯粹的linux环境 本文是采用VMware® Workstation 15 Pro安装centos7桌面版系统来实现的具体安装请参考其他博文资料然后运行gcc -v或g -v测试编译支持 另外其他一些linux系统本人也测试了一下都支持到c11以上但是部分可能支持到新的c20、c23标准会较麻烦 1.4 先睹为快的c11多线程编程示例 建立test.h、test.cpp、main.cpp三个文件内容如下 test.h
#ifndef _THREAD_TEST_H_
#define _THREAD_TEST_H_void func2(void);#endif //_THREAD_TEST_H_ test.cpp
#include test.h#include iostream
#include threadvoid fun1(void)
{std::cout A new thread! std::endl;
};void func2(void)
{std::thread t(fun1);t.join();std::cout Main thread! std::endl;
}; main.cpp
#include test.hint main(int argc, char* argv[])
{func2();return 0;
} 编译g main.cpp test.cpp -o test.exe -pthread -stdc11注意因为程序输出名一致那个编译完就那个直接运行否则其他就会覆盖它。各个工具对c11的支持后win/linux对于多线程的编程就一致了不像c11之前那样跨平台编译c的多线程需要做一堆平台适应性编码。 二、c/c并发编程支持 简单阐述一下c基于多线程并发编程的概念。所谓并发编程是指在一台处理器上“同时”处理多个任务。C/C并发编程主要是程序在进程内通过多线程pthrea或thread(c11)同时并发处理多任务。 2.1 进程与线程 进程和线程是计算机编程领域的两个重要概念。进程可以看作是正在运行的程序的一个实例。它拥有自己的地址空间、文件句柄、系统资源等是一个独立的执行环境。而线程则是进程内的一个执行单元它共享进程的地址空间和系统资源但拥有自己的栈和程序计数器。 进程和线程之间有着紧密的关系。首先一个进程可以包含多个线程这些线程共享进程的资源可以并发地执行不同的任务。同时线程的创建、销毁、调度等都是由进程控制的进程可以为不同的线程分配不同的资源如CPU时间、优先级等。 进程和线程的关系还体现在多核CPU上。多核CPU通常具有多个处理器核心这使得一个进程可以同时在多个核心上运行多个线程从而充分利用系统资源提高程序的执行效率。 2.2 c/c多线程的并发编程 并发编程是指在同一时间内执行多个独立任务的能力。常见的并行编程有多种模型如共享内存、多线程、消息传递等。不过从实用性上讲多线程模型往往具有较大的优势。多线程编程就是在同一进程中同时运行多个线程以达到并发执行的目的。 在c/c中使用线程库来创建和管理线程。多线程模型允许同一时间有多个处理器单元执行统一进程中的代码部分而通过分离的栈空间和共享的数据区及堆栈空间线程可以拥有独立的执行状态以及进行快速的数据共享。 在多线程编程中需要考虑许多问题包括线程同步、竞争条件和死锁等问题。为了避免这些问题可以使用锁和条件变量来同步线程并使用互斥锁来避免竞争条件。另外使用信号量和读写锁也可以提高线程的效率和可靠性。 多线程编程可以提高程序的性能和响应速度但也需要小心处理以避免一些常见的问题例如死锁和竞争条件。c/c多线程编程在编写多线程应用程序时需要仔细考虑各种因素包括线程同步、竞争条件和死锁等问题。 2.3 c11以前的多线程支持 在C11之前C/C一直是一种顺序的编程语言。顺序是指所有指令都是串行执行的即在相同的时刻有且仅有单个CPU的程序计数器指向可执行代码的代码段并运行代码段中的指令。而C/C代码也总是对应地拥有一份操作系统赋予进程的包括堆、栈、可执行的代码及不可执行的数据在内的各种内存区域。 不过随着处理器的发展多核处理器的发展崛起。因此在2000年以后主流的芯片厂商以及编译器开发厂商或组织都开始推广适用于多核处理器的多线程编程模型。而编程语言也逐渐地将线程模型纳入语言特性或者语言库中。相应地各个编程语言也逐渐也开始向并行化的编程方式发展。以顺序执行编程模型为基础的单核处理器的 c/c语言直到c11标准前也无集成于C/C语言特性中的线程特性或者线程库。 在C11之前在C/C中程序中主要使用POSLX 线程pthread和OpenMP编译器指令两种编程模型来完成程序的线程化。其中POSLX 线程是POSIX标准中关于线程的部分程序员可以通过一些pthread线程的API来完成线程的创建、数据的共享、同步等功能。pthread主要用于C语言在类UNIX系统上如FreeBSD、NetBSD、OpenBSD、GNU/Linux、Mac OS X甚至 是Windows上都有实现Windows上pthread的实现并非“原生”主要还是包装为Windows的线程库。不过在使用的便利性上pthread不如后来者OpenMP。OpenMP的编译器指令将大部分的线程化的工作交给了编译器完成而将识别需要线程化的区域的工作交给了程序员这样的使用方式非常简单也易于推广。因此OpenMP得到了业界大多数主流软硬件厂商如 AMD、IBM、Intel、Cray、HP、Fujitsu、Nvidia、NEC、Microsoft、Texas Instruments、Oracle Corporation 等的支持。除去C/C语言外OpenMP还可以用于Fortran语言是现行的一种非常有影响力的使用线程程序优化的编程模型。 来看下c11前调用的pthread.h实现跨线程事务例子 创建test1.h、test1.cpp源文件创建两个线程通过函数指针加载两个事务即函数对一个原型类型进行累加操作为了线程安全使用互斥锁 test1.h
#ifndef _TEST_1_H_
#define _TEST_1_H_
void func3(void);
#endif //_TEST_1_H_ test1.cpp
#include test1.h#include pthread.h
#include iostreamusing namespace std;
static long long total 0;
pthread_mutex_t mutex_ PTHREAD_MUTEX_INITIALIZER;void* func(void *)
{long long i;for(i 0;i 100000000LL;i){pthread_mutex_lock(mutex_);total i;pthread_mutex_unlock(mutex_);}cout pthread_quit \n;return 0;
};void func3(void)
{pthread_t thread1,thread2;if(pthread_create(thread1,NULL,func,NULL)){throw;}if(pthread_create(thread2,NULL, func, NULL)){throw;}pthread_join(thread1, NULL);pthread_join(thread2,NULL);cout total endl;// 9999999900000000
}; 在main.cpp调用
// #include test.h
#include test1.hint main(int argc, char* argv[])
{// func2();func3();return 0;
} 我们要注释掉前面的例子因为这次是指定c98编译g main.cpp test1.cpp -o test.exe -pthread -stdc98编译及运行如下 对比前面例子来说明一下 pthread是C98接口且只支持Linux使用时需要包含头文件#include pthread.h编译时需要链接pthread库,主要是通过一组函数模板集实现多线程。 std::thread是C11接口是跨平台支持的使用时需要包含头文件#include thread编译时需要支持c11标准。thread中封装了pthread的方法所以也需要链接pthread库std::thread是类模板方式来实现多线程。 2.4 c11以后的多线程支持 在C11中标准的一个相当大的变化就是引入了多线程的支持。这使得C/C语言在进行线程编程时不必依赖第三方库和标准。而C/C对线程的支持一个最为重要的部分就是在原子操作中引入了原子类型的概念。 上述代码中基于pthread的方法虽然可行但代码编写却很麻烦。程序员需要为共享变量创建互斥锁并在进入临界区前后进行加锁和解锁的操作。对于习惯了在单线程情况下编程的程序员而言互斥锁的管理无疑是种负担。不过在C11中通过对并行编程更为良好的抽象要实现同样的功能就简单了很多。再看看下面代码。 创建test2.h、test2.cpp源文件 test2.h
#ifndef _TEST_2_H_
#define _TEST_2_H_
void func4(void);
#endif //_TEST_2_H_ test2.cpp
#include test2.h#include atomic
#include thread
#include iostream
using namespace std;
// 原子数据类型
atomic_llong total {0};
void func(int)
{for(long long i 0; i 100000000LL; i){total i;}cout pthread_quit \n;
};void func4(void)
{thread t1(func, 0);thread t2(func, 0);t1.join();t2.join();cout total endl;// 9999999900000000
}; 在main.cpp调用
// #include test.h
// #include test1.h
#include test2.hint main(int argc, char* argv[])
{// func2();// func3();func4();return 0;
} 我们再次注释掉前面的例子因为这次是指定c11编译g main.cpp test2.cpp -o test.exe -stdc11编译及运行如下 在这次的代码中将变量total定义为一个原子数据类型atomic_llong该类型长度等同于C11中的内置类型long long。在C11中开发者不需要为原子数据类型显式地声明互斥锁或调用加锁、解锁的API线程就能够对变量total互斥地进行访问。这里仅定义了C11的线程std::thread变量t1及t2它们都执行同样的函数func并类似于pthread t调用了std::thread成员函数join加入程序的执行。由于原子数据类型的原子性得到了可靠的保障程序最后打印出的total的值和前面是一致的效果。 相比于基于pthread原子操作API而言C11对于原子操作概念的抽象遵从了面向对象的思想C11标准定义的都是所谓的“原子类型”。而传统意义上所谓的“原子操作”则抽象为针对于这些原子类型的操作。直观地看编译器可以保证原子类型在线程间被互斥地访问。这样设计从并行编程的角度看是由于需要同步的总是数据而不是代码因此C11对数据进行抽象会有利于产生行为更为良好的并行代码。而进一步地一些琐碎的概念比如互斥锁、临界区则可以被C11的抽象所掩盖因而并行代码的编写也会变得更加简单。 2.5 线程与互斥锁 上述代码中用到了互斥锁的概念它主要在多线程应用程序中是一种有效的方式来保护共享资源的访问避免竞态条件和数据损坏的问题的常用手段。 C98中的互斥锁是一种常用的同步工具用于保护多线程应用程序中共享资源的访问。下面是使用互斥锁的要点。
创建互斥锁使用pthread_mutex_init()函数初始化一个互斥锁变量。锁定互斥锁使用pthread_mutex_lock()函数锁定一个互斥锁。如果互斥锁已经被锁定则调用线程将阻塞直到互斥锁被释放。解锁互斥锁使用pthread_mutex_unlock()函数解锁一个互斥锁。销毁互斥锁使用pthread_mutex_destroy()函数销毁一个互斥锁。在上述程序中创建了一个互斥锁变量mutex_并定义了一个共享变量total。然后我们创建了2个线程每个线程都会对total变量进行100000000LL次i增量操作。在这个操作中我们使用互斥锁来保护total变量的访问确保每个线程每次i增量操作都是原子的。最后我们输出count变量的值验证程序的正确性。 2.6 跨线程安全问题 c/c开发中的线程安全问题是指在多线程程序中同时有多个线程访问同一段代码或同一份数据时可能会导致数据的不一致性或程序崩溃等问题。为了避免这些问题可以采取以下措施
使用互斥锁或信号量等同步机制来保护共享数据确保同一时间只有一个线程能够访问它。互斥锁是一种最基本的同步机制它能够保证同一时间只有一个线程能够进入临界区。对于非常小的临界区可以使用原子操作来保证数据的一致性。原子操作是指一组操作能够保证在同一时间只有一个线程能够访问某个共享资源从而避免了竞争条件。避免死锁问题。死锁是指在多个线程互相等待对方释放锁的情况下发生的一种死循环。为了避免死锁可以使用避免嵌套锁按照相同的顺序获取锁等方法。避免竞争条件。竞争条件是指在多线程环境下由于访问共享资源的顺序不同导致程序出现错误的情况。为了避免竞争条件可以使用同步机制、原子操作等。尽可能减少临界区。减少临界区的长度能够减小线程争夺锁的时间从而提高程序的并发性能。对于全局变量等共享数据可以使用volatile关键字来保证它们的可见性。volatile关键字能够确保每个线程都能够看到共享变量的最新值。使用线程安全的库函数、类和数据结构。标准库提供了许多线程安全的函数、类和数据结构如线程安全的随机数生成函数rand_r()等。综上所述c/c线程安全问题可以通过使用同步机制、避免死锁和竞争条件、减少临界区长度、使用volatile关键字等方法来解决。同时使用线程安全的库函数、类和数据结构也能够有效地避免线程安全问题。
三、认识c/c的thread 3.1 std::thread类 c11标准引入了std::thread类定义于头文件 thread
//C11起
class thread;类 thread 表示单个执行线程。线程允许多个函数同时执行。线程在构造关联的线程对象时立即开始执行等待任何OS调度延迟从提供给作为构造函数参数的顶层函数开始。顶层函数的返回值将被忽略而且若它以抛异常终止则调用 std::terminate 。顶层函数可以通过std::promise 或通过修改共享变量可能需要同步 std::mutex 与 std::atomic 将其返回值或异常传递给调用方。 std::thread 对象也可能处于不表示任何线程的状态默认构造、被移动、 detach 或 join 后并且执行线程可能与任何 thread 对象无关在 detach 后。没有两个 std::thread 对象会表示同一执行线程 std::thread 不是可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的尽管它可移动构造 (MoveConstructible) 且可移动赋值 (MoveAssignable) 。 std::thread类提供了如下功能
成员类型 定义
native_handle_type (可选) 实现定义 成员类
id 表示线程的 id(公开成员类) 成员函数
(构造函数) 构造新的 thread 对象(公开成员函数)
(析构函数) 析构 thread 对象必须合并或分离底层线程(公开成员函数)
operator 移动 thread 对象(公开成员函数) 观察器
joinable 检查线程是否可合并即潜在地运行于平行环境中(公开成员函数)
get_id 返回线程的 id(公开成员函数)
native_handle 返回底层实现定义的线程句柄(公开成员函数)
hardware_concurrency[静态] 返回实现支持的并发线程数(公开静态成员函数) 操作
join 等待线程完成其执行(公开成员函数)
detach 容许线程从线程句柄独立开来执行(公开成员函数)
swap 交换二个 thread 对象(公开成员函数) 非成员函数
std::swap(std::thread) 特化 std::swap 算法(函数) 其在thread头文件中声明如下
namespace std {class thread {public:// 类型class id;using native_handle_type /* 由实现定义 */;// 构造/复制/销毁thread() noexcept;templateclass F, class... Args explicit thread(F f, Args... args);~thread();thread(const thread) delete;thread(thread) noexcept;thread operator(const thread) delete;thread operator(thread) noexcept;// 成员void swap(thread) noexcept;bool joinable() const noexcept;void join();void detach();id get_id() const noexcept;native_handle_type native_handle();// 静态成员static unsigned int hardware_concurrency() noexcept;};
} 3.2 std::jthread类 值得注意的是在c20标准中引入了一个新的线程类std::jthread类。类 jthread 表示单个执行线程。它拥有通常同 std::thread 的行为除了 jthread 在析构时自动再结合而且能在具体情况下取消/停止。 线程在构造关联的线程对象时在任何操作系统调度延迟后立即开始执行始于作为构造函数参数提供的顶层函数。忽略顶层函数的返回值而若它因抛异常退出则调用 std::terminate 。顶层函数可经由 std::promise 向调用方交流其返回值或异常或通过修改共享变量要求同步见 std::mutex 与 std::atomic 。 使用std::thread时让主线程等待该子线程完成然后主线程再继续执行对于不会停止的线程不要使用join()防止阻塞其他线程或调用detach()(进行线程分离使其不影响其他线程运行。如果join()和detach()都没有被调用析构函数将立即导致程序异常终止。C20引入的std::jthread得以解决这个问题std::jthread对象被析构时会自动调用join()等待执行流结束。 std::jthread的j实际上是joining的缩写不同于 std::thread 在其生命周期结束时调用join()std::jthread 逻辑上保有一个内部的 std::stop_source 类型私有成员它维持共享停止状态。std:: jthread 的构造函数接受一个 std::stop_token 作为其首参数 std::jthread 将从其内部的 stop_source 传递它。这允许函数在其执行中检查是否已请求停止而若已请求则返回。 std::jthread 对象亦可在不表示任何线程的状态在默认构造、被移动、 detach 或 join 后而执行线程可以与任何 std::jthread 对象关联 detach 后。没有二个 std::jthread 对象可表示同一执行线程 std::jthread 非可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 尽管它为可移动构造 (MoveConstructible) 及可移动赋值 (MoveAssignable) 。
//(C20)
成员类型 定义
id std::thread::id
native_handle_type (可选) std::thread::native_handle_type 成员函数
(构造函数) 创建新的 jthread 对象(公开成员函数)
(析构函数) 若 joinable() 为 true 则调用 request_stop() 然后 join() 不论如何都会销毁 jthread 对象。(公开成员函数)
operator 移动 jthread 对象(公开成员函数) 观察器
joinable 检查线程是否可合并即潜在地运行于平行环境中(公开成员函数)
get_id 返回线程的 id(公开成员函数)
native_handle 返回底层实现定义的线程句柄(公开成员函数)
hardware_concurrency[静态] 返回实现支持的并发线程数(公开静态成员函数) 操作
join 等待线程完成其执行(公开成员函数)
detach 容许线程从线程句柄独立开来执行(公开成员函数)
swap 交换二个 jthread 对象(公开成员函数) 停止记号处理(有别于std::thread)
get_stop_source 返回与线程的停止状态关联的 stop_source 对象(公开成员函数)
get_stop_token 返回与线程的共享停止状态关联的 stop_token(公开成员函数)
request_stop 请求执行经由线程的共享停止状态停止(公开成员函数) 非成员函数
swap(std::jthread) 特化 std::swap 算法(函数) 其在thread头文件中声明如下
namespace std {class jthread {public:// 类型using id thread::id;using native_handle_type thread::native_handle_type;// 构造函数、移动与赋值jthread() noexcept;templateclass F, class... Args explicit jthread(F f, Args... args);~jthread();jthread(const jthread) delete;jthread(jthread) noexcept;jthread operator(const jthread) delete;jthread operator(jthread) noexcept;// 成员void swap(jthread) noexcept;[[nodiscard]] bool joinable() const noexcept;void join();void detach();[[nodiscard]] id get_id() const noexcept;[[nodiscard]] native_handle_type native_handle();// 停止记号处理[[nodiscard]] stop_source get_stop_source() noexcept;[[nodiscard]] stop_token get_stop_token() const noexcept;bool request_stop() noexcept;// 特化的算法friend void swap(jthread lhs, jthread rhs) noexcept;// 静态成员[[nodiscard]] static unsigned int hardware_concurrency() noexcept;private:stop_source ssource; // 仅用于阐释};
} 下面来看下std::jthread的使用示例参考了网上代码创建test3.h和test3.cpp tes3.h
#ifndef _TEST_3_H_
#define _TEST_3_H_
void func5(void);
#endif //_TEST_3_H_ test3.cpp
#include test3.h
#include iostream
#include utility
#include thread
#include chrono
using namespace std;void f1(int n)
{for (int i 0; i 5; i) {cout Thread 1 executing\n;n;this_thread::sleep_for(chrono::milliseconds(10));}
}void f2(int n)
{for (int i 0; i 5; i) {cout Thread 2 executing\n;n;this_thread::sleep_for(chrono::milliseconds(10));}
}class foo
{
public:void bar(){for (int i 0; i 5; i) {cout Thread 3 executing\n;n;this_thread::sleep_for(chrono::milliseconds(10));}}int n 0;
};class baz
{
public:void operator()(){for (int i 0; i 5; i) {cout Thread 4 executing\n;n;this_thread::sleep_for(chrono::milliseconds(10));}}int n 0;
};void func5(void)
{int n 0;foo f;baz b;jthread jt0; // t0 不是线程jthread jt1(f1, n 1); // 按值传递jthread jt2a(f2, ref(n)); // 按引用传递jthread jt2b(move(jt2a)); // t2b 现在运行 f2() 。 t2a 不再是线程jthread jt3(foo::bar, f); // t3 在对象 f 上运行 foo::bar()jthread jt4(b); // t4 在对象 b 上运行 baz::operator()jt1.join();jt2b.join();jt3.join();cout Final value of n is n \n;cout Final value of foo::n is f.n \n;// t4 在析构时join
};在main.cpp调用
// #include test.h
// #include test1.h
// #include test2.h
#include test3.hint main(int argc, char* argv[])
{// func2();// func3();// func4();func5();return 0;
} 我们再次注释掉前面的例子因为这次是指定c20编译g main.cpp test3.cpp -o test.exe -stdc20编译及运行如下 3.3 独木难支-线程关联函数集及类集 除了thread和jthread类外c/c标准库为了支持到多线程的同步、安全、死锁等多线程问题及跨线程应用场景在thread库中配套了众多相关的函数和类先睹为快它们的详细说明及案例实践见后面篇章。 管理当前线程的函数,定义于命名空间 this_thread
yield,(C11), 建议实现重新调度各执行线程(函数)
get_id,(C11), 返回当前线程的线程 id(函数)
sleep_for,(C11), 使当前线程的执行停止指定的时间段(函数)
sleep_until,(C11), 使当前线程的执行停止直到指定的时间点(函数) 线程取消,定义于头文件 stop_token
stop_token,(C20), 查询是否已经做出 std::jthread 取消请求的接口(类)
stop_source,(C20), 表示请求停止一个或多个 std::jthread 的类(类)
stop_callback,(C20), 在 std::jthread 取消上注册回调的接口(类模板) (C20 起) 缓存大小访问,定义于头文件 new
hardware_destructive_interference_size,(C17),避免假共享的最小偏移(常量)
hardware_constructive_interference_size,(C17),促使真共享的最大偏移(常量) 互斥,义于头文件 mutex
互斥算法避免多个线程同时访问共享资源。这会避免数据竞争并提供线程间的同步支持。定
mutex,(C11),提供基本互斥设施(类)
timed_mutex,(C11), 提供互斥设施实现有时限锁定(类)
recursive_mutex,(C11), 提供能被同一线程递归锁定的互斥设施(类)
recursive_timed_mutex,(C11),提供能被同一线程递归锁定的互斥设施并实现有时限锁定(类) ,定义于头文件 shared_mutexshared_mutex,(C17), 提供共享互斥设施(类)
shared_timed_mutex,(C14), 提供共享互斥设施并实现有时限锁定(类) 通用互斥管理,定义于头文件 mutex
lock_guard,(C11), 实现严格基于作用域的互斥体所有权包装器(类模板)
scoped_lock,(C17), 用于多个互斥体的免死锁 RAII 封装器(类模板)
unique_lock,(C11), 实现可移动的互斥体所有权包装器(类模板)
shared_lock,(C14), 实现可移动的共享互斥体所有权封装器(类模板) defer_lock_t,(C11),用于指定锁定策略的标签类型(类)
try_to_lock_t,(C11),用于指定锁定策略的标签类型(类)
adopt_lock_t,(C11), 用于指定锁定策略的标签类型(类) defer_lock,(C11),用于指定锁定策略的标签常量(常量)
try_to_lock,(C11),用于指定锁定策略的标签常量(常量)
adopt_lock,(C11),用于指定锁定策略的标签常量(常量) 通用锁定算法
try_lock,(C11),试图通过重复调用 try_lock 获得互斥体的所有权(函数模板)
lock,(C11), 锁定指定的互斥体若任何一个不可用则阻塞(函数模板) 单次调用
once_flag,(C11), 确保 call_once 只调用函数一次的帮助对象(类)
call_once,(C11), 仅调用函数一次即使从多个线程调用(函数模板) 条件变量,定义于头文件 condition_variable
/*条件变量是允许多个线程相互交流的同步原语。它允许一定量的线程等待可以定时另一线程的提醒然后再继续。条件变量始终关联到一个互斥。*/
condition_variable,(C11), 提供与 std::unique_lock 关联的条件变量(类)
condition_variable_any,(C11), 提供与任何锁类型关联的条件变量(类)
notify_all_at_thread_exit,(C11), 安排到在此线程完全结束时对 notify_all 的调用(函数)
cv_status,(C11), 列出条件变量上定时等待的可能结果(枚举) 信号量,定义于头文件 semaphore
/*信号量 (semaphore) 是一种轻量的同步原件用于制约对共享资源的并发访问。在可以使用两者时信号量能比条件变量更有效率。*/
counting_semaphore,(C20), 实现非负资源计数的信号量(类模板)
binary_semaphore,(C20), 仅拥有二个状态的信号量(typedef) 闩与屏障,定义于头文件 latch
/*闩 (latch) 与屏障 (barrier) 是线程协调机制允许任何数量的线程阻塞直至期待数量的线程到达该屏障。闩不能复用屏障能重复使用。*/
latch,(C20), 单次使用的线程屏障(类) .定义于头文件 barrier
barrier,(C20), 可复用的线程屏障(类模板) , (C20 起) Future,定义于头文件 future
/*标准库提供了一些工具来获取异步任务即在单独的线程中启动的函数的返回值并捕捉其所抛出的异常。这些值在共享状态中传递其中异步任务可以写入其返回值或存储异常而且可以由持有该引用该共享态的 std::future 或 std::shared_future 实例的线程检验、等待或是操作这个状态。*/promise,(C11),存储一个值以进行异步获取(类模板)
packaged_task,(C11), 打包一个函数存储其返回值以进行异步获取(类模板)
future,(C11), 等待被异步设置的值(类模板)
shared_future,(C11), 等待被异步设置的值可能为其他 future 所引用(类模板)
async,(C11), 异步运行一个函数有可能在新线程中执行并返回保有其结果的 std::future(函数模板)
launch,(C11),指定 std::async 所用的运行策略(枚举)
future_status,(C11),指定在 std::future 和 std::shared_future 上的定时等待的结果(枚举) Future 错误
future_error,(C11),报告与 future 或 promise 有关的错误(类)
future_category,(C11),鉴别 future 错误类别(函数)
future_errc,(C11),鉴别 future 错误码(枚举)