应该是主线程创建就可以了,异常可能是访问冲突,要在访问数据库的地方设置互斥:
先定义一个CRITICAL_SECTION结构的排斥区对象;
在进程使用之前,先对对象作初始化,调用下面函数:
VOID InitializeCriticalSection( LPCRITICAL_SECTION );
当一个线程使用排斥区时,调用函数
EnterCriticalSection或者TryEnterCriticalSection
要求占用,退出排斥区时 ,调用
LeaveCriticalSection
释放对排斥区对象的占用,供其它线程使用。

解决方案 »

  1.   

    同意pinel() 
    这两天我就是这样做的,应当同步访问!
      

  2.   

    哦,我试试看,但是我现在担心当子线程需要用到该内部线程的ADO访问时,仍然会出现异常。但有一点我需要确认:当不用内部线程做ADO处理时,其他的子线程需要做ADO处理是不是一定得要自己去连接ADO?
      

  3.   

    互斥可以用CRITICAL_SECTION排斥区,可以用Mutex互斥体对象,可以用Semaphore信号对象,可以用Event设置事件对象状态,原理是一样的,就是控制多线程对共享资源的访问。当某一个线程访问共享资源时其他线程就等待。你所说的异常是不是因为这个要搞清楚/
      

  4.   

    不行的,不行的。在我的内部线程中用了同步对象CMutex后,问题仍然出现,我现在贴出部分代码吧。
    BOOL CLogThread::WriteLog(CString strProgramName, short nUnit, short nPort, short nChannel, short nType, CString strLog, short nInOrOut)
    {
    if (m_pLog == NULL)
    {
    if (!InitLog("127.0.0.1" , "c:\\logdb.mdb"))
    {
    AfxMessageBox("Cannot Initialize log dataase.");
    return FALSE;
    }
    }
    BSTR bstrCommandSource = strProgramName.AllocSysString () ;
    BSTR bstrLog = strLog.AllocSysString() ;
    CString strTime = (COleDateTime::GetCurrentTime ()).Format () ;
    BSTR bstrTime = strTime.AllocSysString () ;
    try
    {
    m_mutex.Lock (1000);
    if ((m_pLog->WriteLog (bstrCommandSource ,
       nUnit , nPort , nChannel , nType , bstrLog , bstrTime , nInOrOut)) == E_FAIL)
    {
    ::SysFreeString (bstrCommandSource);
    ::SysFreeString (bstrLog);
    ::SysFreeString (bstrTime);
    m_nLineNumber ++ ;
    if (m_nLineNumber >= 5000)
    {
    m_pLog->ClearLog();
    m_nLineNumber = 0 ;
    }
    return TRUE ;
    }
    else
    {
    ::SysFreeString (bstrCommandSource);
    ::SysFreeString (bstrLog);
    ::SysFreeString(bstrTime);
    return FALSE ;
    }
    m_mutex.Unlock ();
    }
    catch(_com_error &er)
    {
    TRACE(er.ErrorMessage ());
    return FALSE ;
    }

    }
    CLogThread就是这个处理ADO连接的内部线程,然后该线程创建DCOM连接以及创建ADO连接的操作如下:
    BOOL CLogThread::InitLog(CString strIP, CString strLogDB)
    {
    CoInitialize(NULL);
        COSERVERINFO pServInfo ;
    pServInfo.dwReserved1 = 0 ;
    CString servName = strIP;
    _bstr_t bst ;
    bst = servName ;
        pServInfo.pwszName = bst ;
    pServInfo.pAuthInfo = NULL ;
    pServInfo.dwReserved2 = 0 ;
    MULTI_QI qi = {&IID_IsvrLog , NULL , NOERROR} ; HRESULT hr ;

    try
    {
    hr = CoCreateInstanceEx(CLSID_svrLog , NULL ,CLSCTX_REMOTE_SERVER , &pServInfo , 1, &qi);
    // AfxMessageBox("Yes");
    }
    catch (_com_error &er)
    {
    AfxMessageBox(er.ErrorMessage() );
    return FALSE ;
    } if(FAILED(hr))
    {
    CString cs;
    cs.Format("can't create com instance\n  return code : %X",hr);
    switch (hr)
    {
    case 0x80040154:
    cs+="\n\nclass not registered (Proxy/Stub DLL not found?)";
    break;
    case 0x80070005:
    cs+="\n\nAccess Denied";
    break;
    case 0x80080005:
    cs+="\n\nServer execution failed";
    break;
    }
    AfxMessageBox(cs);
    return FALSE ;
    }
       m_pLog = (IsvrLog*)qi.pItf ;
       try
       {
       BSTR str = strLogDB.AllocSysString () ;
       m_pLog->OpenLogDB (str);
       ::SysFreeString (str);
       }
       catch(_com_error &er)
       {
       TRACE(er.ErrorMessage ()) ;
       return FALSE ;
       }
    return TRUE ;
    }
    该线程由一个CLogFile类来创建,并且我只创建一次
    void CLogfile::WriteLog(CString strLog, int type ,int nFlag)
    {
    if (m_pLogThread == NULL)
    {
    m_pLogThread = new CLogThread();
    if (!m_pLogThread->CreateThread (0,0))
    {
    delete m_pLogThread ;
    return ;
    }
    }
    if (m_pLogThread->WriteLog ("Muxdll" , -1,-1,-1,type , strLog , nFlag))
    { }
    }
    在系统的主线程与其他子线程中用一个全局的变量 CLogfile g_fpLog,来引用该对象,
     extern CLogfile g_fpLog;
    g_fpLog.WriteLog(CString strLog, int type ,int nFlag)
    我在主线程中可以将数据写入数据库,但子线程无法调用数据库的写入函数。
    但是如果我在CLogThread的WriteLog函数中,每一次都连接一次DCOM,并且打开数据库连接,则我可以成功地写入数据,但是太占资源和内存了。
      

  5.   

    我现在就是怀疑ADO的线程模型问题,它是不是只能基于当前的线程有效,如果另外一个线程需要用到它,是否在该线程内得要再次创建。
      

  6.   

    异常发生的位置是在子线程访问数据库里发生的。并且我采用的是debug模式,当主线程调用DCOM的写入数据库函数时,它可以进入DCOM的函数进行单步调试,如果是子线程调用写入数据库函数时,则无法进入DCOM的函数进行单步调试。所以我确信,如果子线程需要访问数据库,必须创建数据库连接。而这可能对我的程序造成很大的影响。也许我会放弃。
      

  7.   

    因为 ADO 是基于 COM 模型的,所以每个使用 ADO 对象的线程必须要调用 CoInitialize/CoUnitialize 来初始化 COM 运行环境。所以,我想你的问题很可能在于使用 ADO 对象的线程没有调用 CoInitialize。
      

  8.   

    不会呀,我用过,定义一个数据库操作类存放所有数据库操作,并生成全局变量CDBFun m_dbfun,在个线程中调用其成员,调用前后设置互斥,或在被调用函数中设置,没问题
      

  9.   

    每个使用 ADO 对象的线程必须要调用 CoInitialize/CoUnitialize 来初始化 COM 运行环境ado 是多现成的,不用同步
      

  10.   

    对,每个线程必须都要分别调用Com初始化
      

  11.   

    http://www.csdn.net/expert/topic/544/544226.xml
      

  12.   

    http://www.csdn.net/expert/topic/544/544226.xml
      

  13.   

    http://www.csdn.net/expert/topic/544/544226.xml