M.M*_*M.M 3 c++ windows multithreading atomic
以下代码有效,但它有一个问题:
#include <atomic>
#include "windows.h"
std::atomic<int> foo;
DWORD WINAPI baz(void *) { Sleep(10000); foo.store(1); return 0;}
int main()
{
foo.store(0);
HANDLE h = CreateThread(NULL, 0, baz, NULL, 0, NULL);
while ( !foo.load() )
{
Sleep(0);
}
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
程序在等待时使用最大CPU.
如果我Sleep(0);改为Sleep(1);那么它使用0%的CPU,但我担心一些事情:
load()每毫秒.有没有更好的办法?
背景:我有一些代码正在使用Win32事件唤醒线程,使用WaitForMultipleObjects,但我想知道我是否可以使用std::atomic标志,目的是使代码更简单,更快速和/或更便携.IDK操作系统如何实现WaitForSingleObject和WaitForMultipleObjects,例如它是否Sleep(1)在内部使用或者是否有更智能的技术可用.
注意:它atomic<int>是无锁的; 生成的循环程序集是:
movq __imp_Sleep(%rip), %rbx
movq %rax, %rsi
jmp .L4
.p2align 4,,10
.L5:
xorl %ecx, %ecx
call *%rbx
.L4:
movl foo(%rip), %edx
testl %edx, %edx
je .L5
Run Code Online (Sandbox Code Playgroud)
你不应该等待std::atomic,他们不是为此而设计的.如果你想要一个非忙碌的等待,那么你想要一个std::condition_variable.
A std::condition_variable专门设计为能够等到它发出信号而不使用任何CPU并立即唤醒.
它们的用法有点冗长,你需要将它们与互斥量结合起来,但是一旦你习惯了它们,它们就会很强大:
#include <condition_variable>
#include <mutex>
#include <thread>
std::condition_variable cv;
std::mutex lock;
int foo;
void baz()
{
std::this_thread::sleep_for(std::chrono::seconds(10));
{
auto ul = std::unique_lock<std::mutex>(lock);
foo = 1;
}
cv.notify_one();
}
int main()
{
foo = 0;
auto thread = std::thread(baz);
{
auto ul = std::unique_lock<std::mutex>(lock);
cv.wait(ul, [](){return foo != 0;});
}
thread.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
从 C++20 开始,您可以使用std::atomic<T>::wait(T old). 它的工作原理与条件变量类似,并且不存在自旋锁。
要使用它,您可以使用原子的旧(当前)值调用此方法,并且它将阻塞,直到原子的值更改为不同的值。(请注意,ABA 问题仍然存在——可能会错过对其他值的一些简短更改。)
当值发生变化时,其他线程可以通过调用std::atomic<T>::notify_one()或来告知这一点std::atomic<T>::notify_all()。因此你的例子是:
#include <atomic>
#include "windows.h"
std::atomic<int> foo;
DWORD WINAPI baz(void *) { Sleep(10000); foo.store(1); foo.notify_one(); return 0;}
int main()
{
foo.store(0);
HANDLE h = CreateThread(NULL, 0, baz, NULL, 0, NULL);
foo.wait(0);
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果你想要的是完成信号,那么使用标准库你有两个解决方案 - a condition_variable和a future.由于Mike Vine已经使用前者提供了解决方案,我将展示如何使用后者:
#include <future>
#include <thread>
#include <iostream>
void baz(std::promise<int>& pr)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
pr.set_value(1); // fulfill the prmoise
}
int main()
{
std::promise<int> promise;
auto future = promise.get_future();
auto thread = std::thread(baz, std::ref(promise));
int foo = future.get(); // blocks until promise is fulfilled
std::cout << "Thread yielded: " << foo << std::endl;
thread.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,a condition_variable可以多次通知和等待,但a promise只能满足一次.