不久前,我为Windows函数编写了一个简单的包装类。我编写了一组单元测试,以验证类产生的结果与对API的直接调用相匹配。
最近,我回到了添加有关在不同线程中使用包装类的单元测试。我发现了::GetLastError函数的一些问题。根据MSDN,函数应该保留每个线程的最后一个错误代码:
检索调用线程的最后一个错误代码值。最后一个错误代码是在每个线程基础上维护的.多个线程不会覆盖对方的上次错误代码。
我发现在某些情况下,最后一个错误代码实际上变为零。我成功地用以下简单的程序在单元测试之外复制了这个问题:
#include "stdafx.h"
#include <condition_variable>
#include <mutex>
#include <thread>
#include <Windows.h>
int main(int argc, char* argv[])
{
::DWORD setError1 = 123;
::DWORD setError2 = 456;
// scenario 1 - show that main thread not polluted by sub-thread
const auto act1 = [](::DWORD errorNo)
{
::SetLastError(errorNo);
const auto a = ::GetLastError(); // a = 123
};
::SetLastError(setError2);
const auto b = ::GetLastError(); // b = 456
const auto c = ::GetLastError(); // c = 456
std::thread sub1(act1, setError1);
sub1.join();
const auto d = ::GetLastError(); // d = 0 - WHY???
// scenario 2 - show that sub thread not polluted by main thread
std::condition_variable conditional;
std::mutex mutex;
bool flag = false;
::DWORD e;
const auto act2 = [&mutex, &flag, &e, &conditional](::DWORD errorNo)
{
std::unique_lock<std::mutex> lock(mutex);
::SetLastError(errorNo);
conditional.wait(lock, [&flag] { return flag; });
e = ::GetLastError(); // e = 456 in Windows 8.1, 0 in Windows 10.0.10240.0 - WHY???
};
std::thread sub2(act2, setError2);
{
std::lock_guard<std::mutex> guard(mutex);
::SetLastError(setError1);
flag = true;
}
conditional.notify_all();
sub2.join();
const auto f = ::GetLastError(); // f = 123;
return 0;
}我遇到的问题是d和e
std::condition_variable时会将最后一个错误重置为零。这并不是在使用Windows8.1SDK时重置的。有人能帮我解释一下我看到的结果吗?这是Windows中的一个bug,还是微软C++实现中的一个bug?还是我自己的代码中的一个bug?
发布于 2015-10-30 11:13:09
很简单。下面是发生的事情:
SetLastError打电话。SetLastError。GetLastError并获取最新值,该值是项2中设置的值,而不是项1中设置的值。因此,看看您的代码,以及我的注释:
::SetLastError(setError2); // item 1 from the list above
std::thread sub1(act1, setError1); // item 2
sub1.join(); // item 2
const auto d = ::GetLastError(); // item 3还有你的另一个例子:
::SetLastError(errorNo); // item 1
conditional.wait(lock, [&flag] { return flag; }); // item 2
e = ::GetLastError(); // item 3在每一种情况下,我作为第2项注释的代码都调用API函数,然后调用SetLastError。
https://stackoverflow.com/questions/33434555
复制相似问题