如在主线程中定义了一个对象数据.CArray<CXXObject,CXXObject&> m_objXXGroups;(CXXObject代表一个串口的数据对象)(CXXObject是线程无关的,即它自己保护了多个线程同时访问(读写)它的变量.)现有一个子线程是不断的向m_objXXGroups中的元素写数据。另有多个线程.(即为m_objXXGroups中的每个元素创建了一个线程(每个串口一个线程),不停的取出数据来发送..),它会把通信的结果通过PostMessage(主线程的窗口句柄,WM_XXX,L,P)报告它,让它在主界面中显示结果。<发送线程>
请问:
  1.需要保护m_objXXGroups变量吗?
  2.关于发送线程:
     UINT SendThreadProc(LPVOID lpParameter).
     发送线程组是对这个线程函数多次调用AfxBeginThread产生的。
    问:在SendThreadProc()中定义变量。如long lLength.进行保护吗?因为它有多个线程实例.
  我的程序有时会死掉,不知为什么.

解决方案 »

  1.   

    如果想多个线程都能访问m_objXXGroups的话,必须将m_objXXGroups的指针传给线程函数,另外,访问时最好用CRITICAL_SECTION来对m_objXXGroups加锁来保护访问的安全性!!
      

  2.   

    对于1.如果每个线程只是读取它的内容。需要保护吗?另:我的程序有时候死掉了。好象是线程不执行了.是不是就是没有保护m_objXXGroups.
      

  3.   

    现在每个线程里访问m_objXXGroups的地方我都用临界区保护了,程序还是会死掉。
    但我仔细检查了程序。不会出现死锁。但好象还是死锁了。即程序死掉了.(而且在DEBUG模式下调试.)
      

  4.   

    UINT CStationLedView::DatabaseProc(LPVOID lpParameter)
    {
    AfxOleInit(); CStationLedApp *pApp = (CStationLedApp*) AfxGetApp();
    CStationLedView *pView = (CStationLedView*)lpParameter; ASSERT(pView != NULL && pApp != NULL);
    POSITION pos = pView->m_lstWelInfo.GetHeadPosition();

    pView->m_cs.Lock();
    int nComCount = pView->m_ComGroups.GetSize();
    int nMaxLedCount = 0;
    for (int i=0;i<pView->m_ComGroups.GetSize();i++)
    {
    int nTemp = pView->m_ComGroups[i].m_LedGroups.GetSize();
    if (nMaxLedCount < nTemp)
    nMaxLedCount = nTemp;
    }
    pView->m_cs.Unlock();

    CLedDotData LedDotData;
    while (1)
    {
    if (WAIT_OBJECT_0 == WaitForSingleObject(pView->m_hEvtDatabase,0))
    goto __DO_EXIT; if (!pApp->IsDataBaseOpen())
    pApp->OpenDatabase(pApp->g_szDatabasePathName);

    if (WAIT_OBJECT_0 == WaitForSingleObject(pView->m_hEvtDatabase,0))
    goto __DO_EXIT; if (pApp->IsDataBaseOpen())
    {
    TRACE("Database Thread\n");
    for (int i=0;i<nMaxLedCount;i++)
    {
    for (int k=0;k<nComCount;k++)
    {
    pView->m_cs.Lock();
    int nTempCount = pView->m_ComGroups[k].m_LedGroups.GetSize();
    int nCheckID = pView->m_ComGroups[k].m_LedGroups[i].nCheckID;
    pView->m_cs.Unlock();
    if (nTempCount > i)
    {
    CArray<BUSINFO,BUSINFO&> BusInfos; LedDotData.QueryLineInfo(pApp->m_pConn,nCheckID,
    pApp->g_nSendBeforTime,pApp->g_nCheckBeforTime,BusInfos);
    ASSERT(BusInfos.GetSize() == 1);
    if (BusInfos[0].Flag == 0 && pos != NULL)
    {
    BusInfos[0].Infomation = pView->m_lstWelInfo.GetNext(pos);
    if (BusInfos[0].Infomation == _T(""))
    BusInfos[0].Infomation = _T("热烈祝贺\\n天台车站正式开通");
    if (pos)
    pos = pView->m_lstWelInfo.GetHeadPosition();
    }
    else if (BusInfos[0].Flag == 0)
    BusInfos[0].Infomation = _T("热烈祝贺\\n天台车站正式开通");

    pView->m_cs.Lock();
    pView->m_ComGroups[k].m_LedGroups[i].AddBusInfo(BusInfos);
    pView->m_cs.Unlock();
    }
    if (WAIT_OBJECT_0 == WaitForSingleObject(pView->m_hEvtDatabase,0))
    goto __DO_EXIT;
    }
    }
    }

    for (int k=0;k<pApp->g_nRefreshDatabaseTime;k++)
    {
    if (WAIT_OBJECT_0 == WaitForSingleObject(pView->m_hEvtDatabase,0))
    goto __DO_EXIT;
    Sleep(1000);
    }
    }
    __DO_EXIT:
    pApp->CloseDatabase();
    TRACE(_T("Database Thread Exited!\n"));
    return 0;
    }UINT CStationLedView::SendProc(LPVOID lpParameter)
    {
    SendThreadParam *pParam = (SendThreadParam*)lpParameter;
    HWND hWnd = pParam->hWnd;
    CStationLedView *pView = (CStationLedView*)pParam->pView;
    CStationLedApp *pApp = (CStationLedApp*) AfxGetApp();
    ASSERT(pView != NULL && pApp != NULL && hWnd != NULL); int nComIndex = 0;
    int nPort = pParam->nPort;

    int i,nSize;
    CString szSetting = pParam->szSetting; //////////////////////////////////////////////////////////////////////////
    HANDLE hEvtTemp = ::CreateEvent(NULL,TRUE,FALSE,NULL);
    //////////////////////////////////////////////////////////////////////////

    CLedCom LedCom;
    if (!LedCom.CreateInterface(nPort,szSetting))
    goto __DO_FAILT_EXIT;

    pView->m_cs.Lock();
    nSize = pView->m_ComGroups.GetSize();
    for (i=0;i<nSize;i++)
    {
    if (pView->m_ComGroups[i].nPort == pParam->nPort)
    break;
    }
    pView->m_cs.Unlock(); nComIndex = i;
    ASSERT(nComIndex<= nSize);

    while (1)
    {
    pView->m_cs.Lock();
    int nLedCount = pView->m_ComGroups[nComIndex].m_LedGroups.GetSize();
    pView->m_cs.Unlock(); if (nLedCount == 0) goto __DO_EXIT;

    if (WAIT_OBJECT_0 == ::WaitForSingleObject(pParam->m_hEvtCanExit,0))
    goto __DO_EXIT; ::WaitForSingleObject(hEvtTemp,500); for (i=0;i<nLedCount;i++)
    {
    if (WAIT_OBJECT_0 == ::WaitForSingleObject(pParam->m_hEvtCanExit,0))
    goto __DO_EXIT;
    BUSINFO businfo;
    CByteArray byData;
    CLedDotData LedDotData;
    CFont font;
    LEDEC ret = LEDEC_ERRORSUCCESS; pView->m_cs.Lock();
    BOOL bFlag = pView->m_ComGroups[nComIndex].m_LedGroups[i].GetBusInfo(businfo);
    pView->m_cs.Unlock(); if (!bFlag) continue;

    {
    pView->m_cs.Lock();
    int nAddr = pView->m_ComGroups[nComIndex].m_LedGroups[i].nAddr;
    int nLedID = pView->m_ComGroups[nComIndex].m_LedGroups[i].nLedID;
    int nAreaCount = pView->m_ComGroups[nComIndex].m_LedGroups[i].m_nAreaCount;
    pView->m_cs.Unlock(); if (businfo.Flag == 0)
    {
      //.........
    }
    else if (businfo.Flag == 1)
    {
                                           //...
                                          
    }
    else if (businfo.Flag == 2)
    {
                                              //........

    }
    }
    //Sleep(50);
    }
    }
    __DO_EXIT:
    {
                   //........... }
    }
    __DO_FAILT_EXIT:
    ::SetEvent(pParam->m_hEvtExited);
    TRACE(_T("Com%d Thread Exited!\n"),nPort);
    return 0;
    }
    AfxBeginThread(DataBaseProc,*****);
    for (int i=0;i<nSize;i++)
    {
           ............
        AfxBeginThread(SendProc,....);
    }
      

  5.   

    现在可能找出问题所在。
    我的程序关于多个线程并行操作是正确的.(每个串口一个线程发送数据。一个线程从数据库准备数据。)
    (我把串口线程中的发送数据注释掉,就正确了。)问题好象出在发送上:
       串口发送是用mscomm32.ocx控件来操作的。
       我自己写一个了发送类CLedComm,封装通讯信息.发送数据用mscomm32.ocx来实现.
       在发送线程中创建发送类.(发送类创建CMSComm的实例。)
      ????? 由于是在每个发送线程中创建的CLedComm.因此CLedComm不存在同步问题(是吗?)
       是不是在发送线程中要实现COM的MTA.(比如在一个线程中创建ADO的实例,在创建之间一定还要调用AfxOleInit一样。在发送线程中要实始COM的MTA.)
       倒底应该怎样做?
      

  6.   

    对于1,因为CXXObject已经保护了每一个对象,所以m_objXXGroups不需要再保护。