今天我写了一些代码来测试互斥锁的性能.
这是boost(1.54)版本,在vs2010上使用O2优化编译:
boost::mutex m;
auto start = boost::chrono::system_clock::now();
for (size_t i = 0; i < 50000000; ++i) {
boost::lock_guard<boost::mutex> lock(m);
}
auto end = boost::chrono::system_clock::now();
boost::chrono::duration<double> elapsed_seconds = end - start;
std::cout << elapsed_seconds.count() << std::endl;
Run Code Online (Sandbox Code Playgroud)
这是在VS2013上编译的std版本,也有O2优化:
std::mutex m;
auto start = std::chrono::system_clock::now();
for (size_t i = 0; i < 50000000; ++i) {
std::lock_guard<std::mutex> lock(m);
}
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << elapsed_seconds.count() << std::endl;
Run Code Online (Sandbox Code Playgroud)
有点不同但做同样的事情.我的CPU是Intel Core i7-2600K,我的操作系统是Windows 7 64bit,结果是:0.7020s vs 2.1684s,3.08倍.
boost :: …
在我的计算机(Surface Pro 2)上,只有一个网络适配器,它是一个无线LAN适配器.
我参与了一个小型的C++项目,它使用boost :: asio连接到localhost并完成它的工作,一切都很好.
但今天我发现,如果我从互联网断开WLAN,这个程序不起作用.
boost :: asio的解析器会抛出异常:
tcp::resolver::query query("localhost", "10127");
tcp::resolver resolver(io_service_);
tcp::resolver::iterator iterator;
try {
iterator = resolver.resolve(query);
}
catch (boost::system::system_error& e) {
log(e.what());
}
Run Code Online (Sandbox Code Playgroud)
并且错误消息是:请求的名称有效,但未找到所请求类型的数据.
ping到localhost就可以了.
我感到困惑,本地网络程序是否需要互联网?本地网络程序是否需要LAN适配器?为什么ping工作正常?
在Visual Studio中调试C ++项目时,某些数据断点永远不会命中。
所以我写了一些测试代码:
#include <iostream>
#include <stdint.h>
void test(uint32_t* p)
{
*p = 0;
// set a data breakpoint on p
*((char*)p + 2) = 0x1;
std::cout << *p << std::endl;
}
uint32_t* alloc(size_t offset)
{
char* p = new char[sizeof(uint32_t) + offset];
p = p + offset;
return (uint32_t*)p;
}
int main()
{
test(alloc(0)); // test #1
test(alloc(2)); // test #2
}
Run Code Online (Sandbox Code Playgroud)
如您所见,在功能测试中,* p的值将首先置零,然后将其隐式更改,我得到了一个小端CPU,因此必须为65536。
如果在p(4个字节)上设置数据断点以检测更改,则会得到两个不同的结果:是否命中。它取决于所指向的p的地址。
在我上面的测试代码中,测试#1将命中,而测试#2将不命中,#1和#2之间的区别是alloc(0)和alloc(2)返回的地址。
数据断点不能在未对齐的地址上工作吗?
我最近在做 DLL 注入工作,所以我在谷歌上做了一些研究。现在我知道使用 CreateRemoteThread 是一个好方法。
ASLR(Address space layout randomization,因为Windows Vista)使得kernel32.dll的地址是随机的,但这并不影响整体,因为在一个会话中所有进程的kernel32.dll的基地址是一样的——直到操作系统重置。
所以这段代码通常可能是安全的:
void launchAndInject(const char* app, const char* dll)
{
STARTUPINFOA si = {0};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {0};
if (CreateProcessA(app, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
{
LPVOID loadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if (loadLibrary == NULL) {
return;
}
SIZE_T len = ::strlen(dll) + 1;
LPVOID addr = VirtualAllocEx(pi.hProcess, NULL, len, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (addr == NULL) {
return;
}
if (!WriteProcessMemory(pi.hProcess, addr, dll, len, …Run Code Online (Sandbox Code Playgroud) 假设我有一个C宏定义的产品版本,如下所示:
#define FOO_VERSION 1,0,0,1
Run Code Online (Sandbox Code Playgroud)
我想在运行时打印它:
#define STRING_VALUE(x) #x
int main()
{
std::cout << STRING_VALUE(FOO_VERSION) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这将输出一个字符串"FOO_VERSION",而不是"1,0,0,1".宏参数'FOO_VERSION'未被替换.所以我再次尝试这样:
#define STRING_VALUE(x) STRING_VALUE__(x)
#define STRING_VALUE__(x) #x
int main()
{
std::cout << STRING_VALUE(FOO_VERSION) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它在Visual C++ 2013中有效.
这是一个跨平台的应用程序,尽管只有五行代码.当我使用clang编译代码时,会出现编译时错误:"为类似函数的宏调用提供的参数太多".我猜原因是'FOO_VERSION'中定义的逗号.所以第三个版本:
#define STRING_VALUE(x) STRING_VALUE__(x)
#define STRING_VALUE__(a, b, c, d) #a "," #b "," #c "," #d
int main()
{
std::cout << STRING_VALUE(FOO_VERSION) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这段代码在clang中工作,但是Visual C++会输出一个警告:"编译时宏'STRING_VALUE__'的实际参数不够",当然运行时输出不正确.
我的问题:是否定义了这种预处理器行为?我可以使用STRING_VALUE宏的通用版本吗?
例如,在多线程程序中:
struct TLSObject;
void foo()
{
TLSObject* p = TlsGetValue(slot);
if (p == 0) {
p = new TLSObject;
TlsSetValue(slot, p);
}
// doing something with p
}
Run Code Online (Sandbox Code Playgroud)
第一次在任何线程中调用foo()都会创建一个新的TLSObject。
我的问题是:如何删除TLSObject(如果我不使用boost :: thread和boost :: thread_specific_ptr)?
boost :: thread_specific_ptr可以在线程退出时执行清理工作,但是我想这取决于boost :: thread,不是针对普通的OS线程,而且它很慢。
所以,这就是我所说的:std很复杂.
在VS2013中,这个简单的程序会导致死锁.
#include <thread>
#include <windows.h>
void foo()
{
}
void initialize()
{
std::thread t(foo);
}
BOOL APIENTRY DllMain(HMODULE, DWORD reason, LPVOID)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
initialize();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
在DLLMain中创建一个线程是完全错误的?这不是真的.从Microsoft的"创建DLL的最佳实践"文档:" 如果不与其他线程同步,创建一个线程就可以工作 ".所以CreateThread工作,_beginthreadex工作,boost :: thread工作,但std :: thread不起作用.这是调用堆栈:
ntdll.dll!_NtWaitForSingleObject@12()
KernelBase.dll!_WaitForSingleObjectEx@12()
msvcr120d.dll!Concurrency::details::ExternalContextBase::Block() Line 151
msvcr120d.dll!Concurrency::Context::Block() Line 63
msvcr120d.dll!Concurrency::details::_Condition_variable::wait(Concurrency::critical_section & _Lck) Line 595
msvcp120d.dll!do_wait(_Cnd_internal_imp_t * * cond, _Mtx_internal_imp_t * * mtx, const xtime * target) Line 54
msvcp120d.dll!_Cnd_wait(_Cnd_internal_imp_t * * …Run Code Online (Sandbox Code Playgroud) 行情:
从文档"创建DLL的最佳实践" http://download.microsoft.com/download/a/f/7/af7777e5-7dcd-4800-8a0a-b18336565f5b/DLL_bestprac.doc的Microsoft:
"DLL通常具有复杂的相互依赖性,隐式定义它们必须加载的顺序.库加载器有效地分析这些依赖关系,计算正确的加载顺序,并按顺序加载DLL." [1]
"(在DLLMain中)使用动态C运行时(CRT)中的内存管理功能.如果未初始化CRT DLL,调用这些函数可能会导致进程崩溃." [2]
来自MSDN:http://msdn.microsoft.com/en-us/library/988ye33t.aspx
"_DllMainCRTStartup函数执行多项操作,包括调用_CRT_INIT,它初始化C/C++运行时库并在静态非局部变量上调用C++构造函数.如果没有此函数,运行时库将保持未初始化状态".[3]
"除了初始化C运行时库之外,_DllMainCRTStartup还调用了一个名为DllMain的函数." [4]
问题:
如果您的DLL依赖于CRT DLL,基于[1],将首先加载CRT DLL(首先进行初始化),那么[2]如何发生?
基于[3]和[4],_DllMainCRTStartup将调用_CRT_INIT来初始化CRT,那么[2]会如何发生?
如果一个可执行文件通过"隐式链接"加载你的DLL,你的DLL的_DllMainCRTStartup(和DLLMain)将在可执行文件的入口点(mainCRTStartup或WinMainCRTStartup)之前被调用,基于 [3] - _DllMainCRTStartup调用_CRT_INIT初始化CRT和mainCRTStartup也将初始化CRT,那么CRT究竟发生了什么?
如果你的DLL将在mainCRTStartup之前加载,那么在DLLMain或其他导出函数中调用CRT函数是否安全?
谁会实际初始化CRT DLL?
我很震惊地跟踪这个简单的代码:
#include <thread>
void foo()
{
for (int i = 0; i < 1000000; ++i) {
std::this_thread::sleep_for(std::chrono::nanoseconds(1));
}
}
int main()
{
std::thread t(foo);
t.join();
}
Run Code Online (Sandbox Code Playgroud)
你猜怎么着 ?sleep_for 每次都调用 FreeLibrary !
kernel32.dll!_FreeLibraryStub@4()
msvcr120d.dll!Concurrency::details::DeleteAsyncTimerAndUnloadLibrary(_TP_TIMER * timer) Line 707
msvcr120d.dll!Concurrency::details::_Timer::_Stop() Line 111
msvcr120d.dll!Concurrency::details::_Timer::~_Timer() Line 100
msvcr120d.dll!`Concurrency::wait'::`7'::TimerObj::~TimerObj()
msvcr120d.dll!Concurrency::wait(unsigned int milliseconds) Line 155
test826.exe!std::this_thread::sleep_until(const xtime * _Abs_time) Line 137
test826.exe!std::this_thread::sleep_for<__int64,std::ratio<1,1000000000> >(const std::chrono::duration<__int64,std::ratio<1,1000000000> > & _Rel_time) Line 162
test826.exe!foo() Line 6
Run Code Online (Sandbox Code Playgroud)
为什么 sleep_for 必须调用 FreeLibrary ?
这个程序使用 boost 库需要 2 秒,使用 msvcrt(发布模式)需要 3 分钟以上(失去耐心)。我无法想象。
c++ ×7
visual-c++ ×3
boost ×2
msvc12 ×2
boost-asio ×1
breakpoints ×1
c ×1
c++11 ×1
crt ×1
debugging ×1
dll ×1
macros ×1
msvcrt ×1
mutex ×1
performance ×1
windows ×1
wlan ×1