开了一个新坑,在看UE的多线程,发现在UE5/Source/Runtime/Core/HAL/Allocators/ThreadSafeBool.h下有:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEPRECATED. Please use `std::atomic<bool>`
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

燧重新看起STL的并发库

Threads

std::thread

	FString hello(TEXT("hello"));
	int pastValue=114514;
	std::thread testThread([=](FString s,int pastValue)
	{
		UE_LOG(LogTemp,Warning,TEXT("%s%d"),*s,pastValue);
	},hello,std::ref(pastValue));
	std::stringstream out;
	out<<testThread.get_id();
	FString sThreadId(out.str().c_str());
	UE_LOG(LogTemp,Warning,TEXT("the Thread is is:%s"),*sThreadId);
	if (testThread.joinable())
	{
		testThread.join();
	}
LogTemp: Display: Hello World
LogTemp: Warning: the Thread is is:57668
LogTemp: Warning: hello114514

std::thread并不一定代表一个线程实例,当调用

template< class F, class... Args >
explicit thread( F&& f, Args&&... args );

构造时,才代表创建一个线程实例,观察std::thread的构造函数发现,它不支持拷贝构造,也不支持拷贝复制,显然一个线程实例仅能被一个std::thread对象代表

about join, detach 和传入参数

因为线程实例在床架完成后立即执行,所以join/detach仅仅对线程的生命周期进行控制, 确保主线程结束是子线程结束,join阻塞主线程指导子线程结束

显然当子线程结束时或thread不代表一个线程实例时,std::thread::joinable返回false;

显然,std::thread需要手动调用join同步主线程和子线程,很麻烦,c++20提供了一个在析构函数join的std::jthread,符合RAII的思想

    std::jthread jthread([&](){
        int r=0;
        for (int i = 0; i < 1000; ++i) {r++;}
        std::cout<<r<<'\n';
    });
    std::cout<<"main"<<'\n';

Futures

在需要异步执行程序时,往往需要接收异步执行的信息,这需要子线程传递参数给其他线程,stl中为这一操作提供了一系列工具

    std::future<std::string> future=std::async([&](){
        for (int i = 0; i < 10; i++){
            std::cout<<"process: "<<i<<'\n';
            std::this_thread::sleep_for(std::chrono::milliseconds(10l));
        }
        return "success"s;
    });
    future.wait();
    std::cout<<"hello"<<'\n';
    auto ret=future.get();
    std::cout<<ret<<'\n';

std::async&std::future

创建一个线程,返回一个future对象在调用.get()函数是阻塞主线程等待线程执行完成,获得线程返回值

std::future提供了一个提前阻塞等待线程完成wait();

也可以选择等待一段时间,检查是否运行完成

同样还有wait_until()等待到一个time_point

    while (true){
        if (auto stat=future.wait_for(std::chrono::milliseconds(200l));stat!=std::future_status::ready){
            std::cout<<"waiting\n";
        }else{
            std::cout<<"finish\n";
            break;
        }
    }

在std::async中第一个参数可以传入std::launch::deferred来决定子线程只在get()被调用时才执行,这不是狭义上的多线程,满足函数式编程的范式,可以用于惰性求值

    std::future<std::string> future=std::async(std::launch::deferred,[&](){
        for (int i = 0; i < 10; i++){
            std::cout<<"process: "<<i<<'\n';
            std::this_thread::sleep_for(std::chrono::milliseconds(100l));
        }
        return "success"s;
    });
    std::cout<<"hello"<<'\n';
    auto ret=future.get();
    std::cout<<ret<<'\n';

std::promise

std::future的底层实现与此相关,当需要自己创建线程时,可以引用获取std::promise调用set_value方法,之后调用get_future()方法获取future对象

    std::promise<std::string> promise;
    std::jthread thread([&](){
        for (int i = 0; i < 10; i++){
            std::cout<<"process: "<<i<<'\n';
            std::this_thread::sleep_for(std::chrono::milliseconds(100l));
        }
        promise.set_value("success"s);
    });
    std::cout<<"hello"<<'\n';
    auto future=promise.get_future();
    auto ret=future.get();
    std::cout<<ret<<'\n';

future库还提供了异常处理

future_error

(C++11)

reports an error related to futures or promises
(class)

future_category

(C++11)

identifies the future error category
(function)

future_errc

(C++11)

identifies the future error codes
(enum)