我实际上面临一个巨大的问题:我有一个单身人士课程。我的程序是一个多线程MFC,因此可以从不同的线程调用单例的构造函数。我用一个互斥锁包围了单例实例 - getter函数,以避免死锁和多个构造。下面的调用意味着函数在第一次直接失败。
该函数看起来像(LOG_MSG宏将给定的字符串记录到我的日志文件中):
MyClass& MyClass::singleton ()
{
LOG_MSG("MyClass::singleton -> jump in");
static CMutex oInitMutex;
try
{
CSingleLock oSingleLock((CSyncObject *) &oInitMutex, TRUE);
LOG_MSG("!!! SINGLETON LOCK OKAY !!!");
static MyClass oMyClassInstance;
LOG_MSG("!!! SINGLETON CONSTRUCTION OKAY !!!");
return oMyClassInstance;
}
catch(...)
{
CString excMsg("Unexpected exception by creating MyClass singleton instance!");
LOG_MSG(excMsg);
throw excMsg;
}
}
我已经想通了,单例对象的构造不会失败(因为我们得到了“!!! SINGLETON CONSTRUCTION OKAY !!!”消息)。
日志输出说:
09.04.2013 ;07:14:51:832;"MyClass::singleton -> jump in"
09.04.2013 ;07:14:51:841;"!!! SINGLETON LOCK OKAY !!!"
... (constructor logs => NOTHING unexpected in it!!! everything runs fine, as they must!!!)
09.04.2013 ;07:14:52:125;"!!! SINGLETON CONSTRUCTION OKAY !!!"
09.04.2013 ;07:14:52:170;"Unexpected exception by creating MyClass singleton instance!"
这意味着什么?何时返回语句会抛出异常?请帮我解决这个问题...
答案 0 :(得分:6)
虽然这不能解答您的特定问题,但它仍然是您整体问题的解决方案:您根本不需要互斥锁 C ++ 11标准[stmt.dcl] §4指定(当谈论函数本地的static
变量时):
如果控件在变量的同时进入声明 在初始化时,并发执行应等待完成 初始化。 88 如果控制重新进入声明 在初始化变量时递归地,行为是 未定义。
注88的地方是:
注88:实现不得引入任何死锁 执行初始化程序。
换句话说,编译器会为您引入同步;无需手动执行此操作。
答案 1 :(得分:1)
<强> SOLUTION:强>
我弄清楚了问题,这并不容易。为了从我的错误中吸取教训,我 将共享代码,导致失败。
在构造函数中,我以不正确的方式使用
sscanf
函数调用:const char* sBuffer; // some stuff here that fills the sBuffer up sscanf(sBuffer, "%X %X %X %X", &tags_[0], &tags_[1], &tags_[2], &tags_[3]);
数组在单例类中定义为:
private: char tags_[4];
注意:格式代码可以唤醒特定类型的变量 写入数据。例如:在我的情况下,
tags_
数组应该 是一个整数数组而不是字符数组。自单身类以来 索引第2,第3和第4个元素后应存储tags_
,sscanf
函数将写入未定义的内存位置, 关于静态类的数据会覆盖一些东西 然而,它引起了多次实例化:这可以通过以下方式避免 静音,但在这种情况下,互斥对象将被覆盖。 可以找到关于(s)scanf所需类型的更多信息here和here。
<强>结论:强>
要聪明并且意识到使用C功能/低级别呼叫。付出很多 注意输入参数,不仅是它们的值,还有它们的类型 太。如果您按预期支持其他类型,则程序的行为将是 undefined,但你不会得到编译错误:很难找到 那个问题稍后。