to 回复人: freelybird(阿愚) ( ) 信誉:100 2002-04-28 10:05:00 得分:0 没错,用普通变量来互斥是肯定不行的。 to 回复人: localvar(localvar) ( ) 信誉:100 我说过了,对话框是可以让消息重入的。当然也包括 messagebox 不管是否重入,如果使用了 线程互斥机制,就一定不会出现问题。我建议你仔细查一查你的申请内存和释放内存,以及使用内存的代码。看看是否有使用内存越界等等。
/*******我没有写过 dde 程序,但我看了你的代码,发现一个可能存在的问题:*****/OnTimer( ... ) ... ... if(m_bConnected) { HDDEDATA hData = NULL; DWORD dwSize = 0; BYTE buf[64]; /****注意 大小只有 64 bytes, 我的意见是修改为 buf[65] ********/ SENDPACKITEM* pItem = (SENDPACKITEM*)(m_pSendBuf + sizeof(SENDPACKHEADER)); CString strText; //我的测试环境中m_wPointCount = 500 for(WORD i=0; i<m_wPointCount; i++) { hData = DdeClientTransaction(NULL, 0, m_hConv, m_pPointInfo[i].hszName, 1, XTYP_REQUEST, TIME_OUT, NULL); if(hData == NULL) continue; dwSize = DdeGetData(hData, buf, 64, 0); buf[dwSize] = '\0'; /***** 注意前面定义,如果读出来刚好是 dwSize == 64 byte 那么,这个代码就可能是问题**********//********* 关于 DdeGetData msdn 上是这么说的 Return Values If the pDst parameter points to a buffer, the return value is the size, in bytes, of the memory object associated with the data handle or the size specified in the cbMax parameter, whichever is lower. If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object associated with the data handle. ***********/
to scklotz(晓春): 我知道这个问题,如果你也看了我其他部分的代码的话,你会发现我处理缓冲区是非常小心的。程序中有少数几个地方直接指定了缓冲区的大小,但是在这些地方,我可以保证在最终的运行环境中缓冲区不会溢出。在用excel进行测试的时候,我取过来的数据也仅有几个字节而已,所以不会是这出错。问题我想我已经找到了,他出在对DdeClientTransaction的调用上, msdn上说以同步方式对它的调用不会阻止程序对其他用户输入的响应。也就是说对它的调用过程,和显示一个对话框是类似的。很有可能是在对它进行调用时,我删除缓冲区的代码执行了,最终导致出错。至于线程同步机制不起作用,我想是不是因为,这些机制只能用于不同线程之间,而在同一个线程上使用无效呢?
LeaveCriticalSection
CEvent event;
WaiteForSingleObject()
event.SetEvent
cevent我试试看
Thread1 if(!gFlag)
{
//delete something1 //step 1
//delete something2 //step 3
}Thread2BOOL gFlag=FALSE;
OnTimer()
{
gFlag=TRUE; //step 2
... //step 4
gFlag=FALSE;
}执行顺序如上,则step4出错. (2) 所以说,怎样理解互斥,简单地说,就是把你要做的东西全部做完,在你做完之前,另一块互斥区不能执行.(3) 用临界区互斥
CCriticalSection gFlagThread1
gFlag.Lock()
...
gFlag.Unlock()
Thread2
gFlag.Lock()
//delete something
gFlag.Unlock()
2. 我程序只有一个函数释放与此相关内存,我对它已经作了同步处理。
3. 我所有的代码在同一个线程之中。
没错,用普通变量来互斥是肯定不行的。
to 回复人: localvar(localvar) ( ) 信誉:100 我说过了,对话框是可以让消息重入的。当然也包括 messagebox
不管是否重入,如果使用了 线程互斥机制,就一定不会出现问题。我建议你仔细查一查你的申请内存和释放内存,以及使用内存的代码。看看是否有使用内存越界等等。
...
...
if(m_bConnected)
{
HDDEDATA hData = NULL;
DWORD dwSize = 0;
BYTE buf[64]; /****注意 大小只有 64 bytes, 我的意见是修改为 buf[65] ********/
SENDPACKITEM* pItem = (SENDPACKITEM*)(m_pSendBuf + sizeof(SENDPACKHEADER));
CString strText;
//我的测试环境中m_wPointCount = 500
for(WORD i=0; i<m_wPointCount; i++)
{
hData = DdeClientTransaction(NULL, 0, m_hConv, m_pPointInfo[i].hszName, 1, XTYP_REQUEST, TIME_OUT, NULL);
if(hData == NULL)
continue;
dwSize = DdeGetData(hData, buf, 64, 0);
buf[dwSize] = '\0'; /***** 注意前面定义,如果读出来刚好是 dwSize == 64 byte 那么,这个代码就可能是问题**********//********* 关于 DdeGetData msdn 上是这么说的 Return Values
If the pDst parameter points to a buffer, the return value is the size, in bytes, of the memory object associated with the data handle or the size specified in the cbMax parameter, whichever is lower. If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object associated with the data handle.
***********/
我知道这个问题,如果你也看了我其他部分的代码的话,你会发现我处理缓冲区是非常小心的。程序中有少数几个地方直接指定了缓冲区的大小,但是在这些地方,我可以保证在最终的运行环境中缓冲区不会溢出。在用excel进行测试的时候,我取过来的数据也仅有几个字节而已,所以不会是这出错。问题我想我已经找到了,他出在对DdeClientTransaction的调用上, msdn上说以同步方式对它的调用不会阻止程序对其他用户输入的响应。也就是说对它的调用过程,和显示一个对话框是类似的。很有可能是在对它进行调用时,我删除缓冲区的代码执行了,最终导致出错。至于线程同步机制不起作用,我想是不是因为,这些机制只能用于不同线程之间,而在同一个线程上使用无效呢?
还有一段代码也有问题:OnTimer( ... )
...
...
Send(sizeof(SENDPACKHEADER) + sizeof(SENDPACKITEM)*m_wPointCount);
SetTimer(IDT_TIMER, 1000, NULL);
}// m_critical_section.Unlock(); ShowStatus();
CDialog::OnTimer(nIDEvent);
}
如果 Send 调用失败,会触发: CloseAll(), 消息框
再之后,SetTimer ( CloseAll 调用过 KillTimer )
进入 OnTimer 代码
而此时, CloseAll 已被调用。
实际上,你必须检查 Send 的返回值。
触发消息处理函数:LONG CJhDlg::OnParterClosed(WPARAM, LPARAM)
{
CloseAll();
CString str((LPTSTR)IDS_DDE_PARTER_CLOSED);
MessageBox(str, NULL, MB_OK|MB_ICONINFORMATION);
return 0;
}也是间接除法 CloseAll
照你所说的,那问题可能就是这样的:DdeDdeClientTransaction 过程中,可能调用了 DdeCallback
由于 DdeDdeClientTransaction 并不阻塞消息循环,
所以 消息处理被调度 OnParterClosed
然后是 CloseAll这样就可能出现问题了。你可以在 OnParterClosed 加入一条 TRACE 看看效果如何。
触发消息处理函数:LONG CJhDlg::OnParterClosed(WPARAM, LPARAM)
{
CloseAll();
CString str((LPTSTR)IDS_DDE_PARTER_CLOSED);
MessageBox(str, NULL, MB_OK|MB_ICONINFORMATION);
return 0;
}也是间接除法 CloseAll
照你所说的,那问题可能就是这样的:DdeDdeClientTransaction 过程中,可能调用了 DdeCallback
由于 DdeDdeClientTransaction 并不阻塞消息循环,
所以 消息处理被调度 OnParterClosed
然后是 CloseAll这样就可能出现问题了。你可以在 OnParterClosed 加入一条 TRACE 看看效果如何。
而且他还会引起一个问题,如果我的线程同步代码起作用的话,会发生死锁。
谢谢。
但是这不是引起上面错误的原因,因为Send失败,会弹出消息框(或,如果有同步机制的话,会发生死锁),而实际上出错时并没有出现这种情况.
虽然没有从资料上证实,但是线程同步机制在这里好像不起作用。不知你对此有什么看法?
另:你距一星会员还差多少分?如果不多的话我就给你凑够了吧 :)
CCriticalSection 在单线程里没有效果,返回到原始时代,还是用变量来控制吧,
用成员变量或者局部静态变量
例如如下的代码回工作得很好:OnTimer( ... )... ... static b = false; if( ! b ) {
b = true;
time_t t = time(NULL);
TRACE( "===%d start===\n", t );
MessageBox( "var timer" );
TRACE( "===%d end ===\n", t );
b = false;
}... ...
相信你应该知道怎么做。
而不是根据线程同步机制。在 MessageBox 之类的半阻塞函数中,
我认为有点类试于递归调用,变量之间的赋值与读取不会受到
类似多线程那样的影响。
1. OnTimer一般情况下不能重入,但在有对话框或某些特殊函数时,可以重入。
2.线程同步机制只适用于多线程,对单线程无效。
例如,线程1
mov var -> register
之后被操作系统中断线程2
mov register -> var
之后被操作系统中断线程1
cmp register xxx这个时候,线程1 得到的值就是有问题的值。
{
mutex1.Lock();
...
mutex.Unlock();
}void func1()
{
mutex1.Lock();
func2(); //如果单线程可行的话,这里将发生死锁
mutex.Unlock();
}