我很困惑,我认为我的调试器对我说谎.我的代码中有以下循环:
MyClass::UploadFile(CString strFile)
{
...
static DWORD dwLockWaitTime = EngKey::GetDWORD(DNENG_SERVER_UPLOAD_LOCK_WAIT_TIME, DNENG_SERVER_UPLOAD_LOCK_WAIT_TIME_DEFAULT);
static DWORD dwLockPollInterval = EngKey::GetDWORD(DNENG_SERVER_UPLOAD_LOCK_POLL_INTERVAL, DNENG_SERVER_UPLOAD_LOCK_POLL_INTERVAL_DEFAULT);
LONGLONG llReturnedOffset(0LL);
BOOL bLocked(FALSE);
for (DWORD sanity = 0; (sanity == 0 || status == RESUMABLE_FILE_LOCKED) && sanity < (dwLockWaitTime / dwLockPollInterval); sanity++)
{
...
Run Code Online (Sandbox Code Playgroud)
在我的程序过程中,这个循环已被执行了数百次,并且两个静态变量在代码中的任何地方都没有改变,当它们被静态初始化并在循环条件下读取时,它们只被写入一次其他地方.由于它们是从Windows注册表中读取的用户设置,因此它们几乎总是具有dwLockWaitTime = 60和dwLockPollInterval = 5的常量值.因此循环始终为60/5.
很少,我得到一个崩溃转储,显示这行代码已经抛出除零错误.我已经检查了WinDbg所说的内容,它显示:
FAULTING_IP:
procname!CServerAgent::ResumableUpload+54a [serveragent.cpp @ 725]
00000001`3f72d74a f73570151c00 div eax,dword ptr [proc!dwLockPollInterval (00000001`3f8eecc0)]
EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 000000013f72d74a (proc!CServerAgent::ResumableUpload+0x000000000000054a)
ExceptionCode: c0000094 (Integer divide-by-zero)
ExceptionFlags: 00000000
NumberParameters: 0
ERROR_CODE: (NTSTATUS) 0xc0000094 - …Run Code Online (Sandbox Code Playgroud) 我记得读过在方法中声明的静态变量不是线程安全的.(请参阅托德加德纳提到的梅耶的单身人士怎么样)
Dog* MyClass::BadMethod()
{
static Dog dog("Lassie");
return &dog;
}
Run Code Online (Sandbox Code Playgroud)
我的库为最终用户生成C++代码,以便作为其应用程序的一部分进行编译.它生成的代码需要以线程安全的跨平台方式初始化静态变量.我想使用boost::call_once互斥变量初始化,但最后用户会暴露于Boost依赖项.
有没有办法让我这样做而不强迫最终用户有额外的依赖?
例如,node::node()以下代码段中的构造函数访问全局变量node::count而::tail没有任何多线程保护.C++标准是否保证输出始终是0 1 2(无论顺序如何)的排列?
#include <stdio.h>
struct node *tail;
struct node
{
static int count;
int index;
node *prev;
node()
{ index = count++; prev = tail; tail = this; }
};
int node::count;
node one, two[2];
int main(int argc, char *argv[])
{
for(node *p = tail; p; p = p->prev)
printf("%d\n", p->index);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找基于(适用)标准的答案,而不是针对实现或编译器特定行为.有许多对SO有关的问题,但它不是完全清楚他们是如何直接适用于这个特定的和相当基本情况(是C++中的静态成员变量的初始化是线程安全的?,是本地静态变量的初始化线程安全的C++ 11 ?等).
我有一堆线程.他们应该访问包含配置数据的单例,该数据在创建单例时初始化一次.因此在第一次访问.因此,对单身人士的进一步行动只是只读的.在这种情况下,我是否需要关键部分?
我刚才读到,这个结构:
const bg::AppSettings& bg::AppSettings::GetInstance()
{
static AppSettings instance;
return instance;
}
Run Code Online (Sandbox Code Playgroud)
是一个创建单例的线程安全和工作方式?!我是否正确,每次调用此方法时,静态AppSettings变量都是相同的?!我对这个问题的范围有点困惑......
我的正常方法是使用unique_ptr作为我班级的静态成员......但这似乎有用......有人可以向我解释一下,这里发生了什么?!
顺便说一下:const在这里有意义吗?!
例如,以下代码是否可以为其中一个线程打印"3"?
int foo()
{
static int a = 1;
return ++a;
}
void thread1()
{
cout<<foo()<<endl;
}
void thread2()
{
cout<<foo()<<endl;
}
Run Code Online (Sandbox Code Playgroud)
编辑:这是C++ 98
我们可以通过调用函数std::this_thread::get_id()的开头来获取主线程的id,main就像这个答案所暗示的那样.然后我们可以将它存储id在一个全局变量中,并与一个调用进行比较std::this_thread::get_id().
但是,这迫使我们改变main功能.有没有办法创建一个这样做的库函数?我正在考虑使用用std::this_thread::get_id()表达式初始化的全局变量.由于全局变量(具有静态持续时间的变量)相对较早地初始化,因此在初始化这些变量之前,不太可能(但不是不可能,参见:延迟动态初始化)生成线程.
我还可以使用辅助函数初始化全局变量,该函数枚举所有线程并选择具有最早创建时间的线程(基于此答案).
我是多线程的新手,所以非常欢迎任何建议或指导.