C++ 线程

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) 。

成员类型
	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)(C++11)特化 std::swap 算法(函数)
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
 
void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 1 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
 
void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
 
class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 3 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};
 
class baz
{
public:
    void operator()()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 4 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};
 
int main()
{
    int n = 0;
    foo f;
    baz b;
    std::thread t1; // t1 不是线程
    std::thread t2(f1, n + 1); // 按值传递
    std::thread t3(f2, std::ref(n)); // 按引用传递
    std::thread t4(std::move(t3)); // t4 现在运行 f2() 。 t3 不再是线程
    std::thread t5(&foo::bar, &f); // t5 在对象 f 上运行 foo::bar()
    std::thread t6(b); // t6 在对象 b 的副本上运行 baz::operator()
    std::thread t7{[]{ std::cout << "Thread 7 executing\n"; }}; // std::thread 的参数也可以是函数对象或者 lambda
    t2.join();
    t4.join();
    t5.join();
    t6.join();
    t7.join();
    std::cout << "Final value of n is " << n << '\n';
    std::cout << "Final value of f.n (foo::n) is " << f.n << '\n';
    std::cout << "Final value of b.n (baz::n) is " << b.n << '\n';
}

join

阻塞当前线程直至 this 所标识的线程结束其执行。this 所标识的线程的完成同步于对应的从 join() 成功返回。*this 自身上不进行同步。同时从多个线程在同一thread 对象上调用 join() 构成数据竞争,导致未定义行为。

joinable

检查 std::thread 对象是否标识活跃的执行线程。具体而言,若 get_id() != std:🧵:id() 则返回 true 。故默认构造的 thread 不可结合。结束执行代码,但仍未结合的线程仍被当作活跃的执行线程,从而可结合。

#include <iostream>
#include <thread>
#include <chrono>
 
void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}
 
int main()
{
    std::thread t;
    std::cout << "before starting, joinable: " << std::boolalpha << t.joinable()
              << '\n';
 
    t = std::thread(foo);
    std::cout << "after starting, joinable: " << t.joinable() 
              << '\n';
 
    t.join();
    std::cout << "after joining, joinable: " << t.joinable() 
              << '\n';
}
输出:

before starting, joinable: false
after starting, joinable: true
after joining, joinable: false

detach

从 thread 对象分离执行线程,允许执行独立地持续。一旦该线程退出,则释放任何分配的资源。调用 detach 后 *this 不再占有任何线程。

swap

交换二个 thread 对象的底层柄。

#include <iostream>
#include <thread>
#include <chrono>
 
void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}
 
void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}
 
int main()
{
    std::thread t1(foo);
    std::thread t2(bar);
 
    std::cout << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';
 
    std::swap(t1, t2);
 
    std::cout << "after std::swap(t1, t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';
 
    t1.swap(t2);
 
    std::cout << "after t1.swap(t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';
 
    t1.join();
    t2.join();
}

可能的输出:

thread 1 id: 140185268262656
thread 2 id: 140185259869952
after std::swap(t1, t2):
thread 1 id: 140185259869952
thread 2 id: 140185268262656
after t1.swap(t2):
thread 1 id: 140185268262656
thread 2 id: 140185259869952
posted @ 2022-03-02 22:58  放飞梦想C  阅读(174)  评论(0编辑  收藏  举报