Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 安全地同步COM线程_C++_Multithreading_Com_Boost_Synchronization - Fatal编程技术网

C++ 安全地同步COM线程

C++ 安全地同步COM线程,c++,multithreading,com,boost,synchronization,C++,Multithreading,Com,Boost,Synchronization,过去我在多线程方面做了很多工作,但我对COM还是相当陌生的。无论如何,我的问题是: 我创建了一个工作线程,它注册为STA,并创建了一个COM对象。然后工作线程和主线程尝试相互通信。使用comarshalinterreadinterfaceinstream和CoGetInterfaceAndReleaseStream,我可以让线程调用另一个线程中COM对象的方法 下面是工作线程的外观: void workerThread() { CoInitialize(NULL); MyLib::IFo

过去我在多线程方面做了很多工作,但我对COM还是相当陌生的。无论如何,我的问题是:

我创建了一个工作线程,它注册为STA,并创建了一个COM对象。然后工作线程和主线程尝试相互通信。使用
comarshalinterreadinterfaceinstream
CoGetInterfaceAndReleaseStream
,我可以让线程调用另一个线程中COM对象的方法

下面是工作线程的外观:

void workerThread()
{
  CoInitialize(NULL);
  MyLib::IFooPtr foo = ...; // create my COM object

  // Marshall it so the main thread can talk to it
  HRESULT hr = CoMarshalInterThreadInterfaceInStream(foo.GetIID(),
                                                     foo.GetInterfacePtr(),
                                                     &m_stream);
  if (FAILED(hr)) {
    // handle failure
  }

  // begin message loop, to keep this STA alive
  MSG msg;
  BOOL bRet;
  while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
  { 
    if (bRet == -1)  break;

    DispatchMessage(&msg); 
  }
}
在主线程中:

// launch the thread
m_worker = boost::thread (&workerThread);

// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));
m_startupDone = CreateEvent (NULL, FALSE, FALSE, NULL);
m_threadStartCount = <number of workerthreads>

// launch the thread(s)
m_worker = boost::thread (&workerThread);
m_worker2 = boost::thread (&workerThread);
...

// now wait for tall the threads to create the COM object(s)
if (WAIT_OBJECT0 != WaitForSingleObject(m_startupDone, ...))
{
   // handle failure like timeout
}
// By now all COM objects are guaranteed created and marshaled, unmarshall them all in main
// here must check if all threads actually succeeded (could be as simple as m_stream is not NULL)

// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));

但是如何将
boost::thread.join()
boost::condition.wait()
MsgWaitForMultipleObjects
混合使用呢?这是可能的,还是我必须做些别的事情来避免竞争条件?

您的主线程有一个消息队列(必须是,因为它是STA主机),为什么不直接向它发送消息呢?发布一条用户消息(WM_user+X),您的普通主线程消息泵可以将此用户消息作为通知处理,通知COM对象已将接口封送到流中,并且主线程可以安全地调用
CogeInterface和LeaseStream

我必须指出,在您当前的设计中,您的工作线程基本上只不过是运行一个额外的消息泵。主线程对接口上任何方法的任何调用都将被阻塞,等待工作线程从其消息队列中提取消息,处理调用,响应,然后主线程将继续。所有操作的速度至少与将COM对象托管在主线程中一样慢,再加上在两个STA之间来回进行COM封送的开销。由于COM STA的工作方式,两个线程之间基本上没有任何并发性。你确定这就是你想要的吗

编辑

(省略一些细节,如线程数、超时处理、为每个工作线程分配流/IID/CLSID等)

在.h中:

HANDLE m_startupDone;
volatile int m_threadStartCount;
工作线程:

void workerThread()
{
  CoInitialize(NULL);
  MyLib::IFooPtr foo = ...; // create my COM object

  // Marshall it so the main thread can talk to it
  HRESULT hr = CoMarshalInterThreadInterfaceInStream(foo.GetIID(),
                                                     foo.GetInterfacePtr(),
                                                     &m_stream);
  if (FAILED(hr)) {
    // handle failure
    // remember to decrement and signal *even on failure*
  }

  if (0 == InterlockedDecrement(&m_threadStartCount))
  {
     SetEvent (m_startupDone);
  } 

  // begin message loop, to keep this STA alive
  MSG msg;
  BOOL bRet;
  while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
  { 
    if (bRet == -1)  break;

    DispatchMessage(&msg); 
  }
}
在主线程中:

// launch the thread
m_worker = boost::thread (&workerThread);

// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));
m_startupDone = CreateEvent (NULL, FALSE, FALSE, NULL);
m_threadStartCount = <number of workerthreads>

// launch the thread(s)
m_worker = boost::thread (&workerThread);
m_worker2 = boost::thread (&workerThread);
...

// now wait for tall the threads to create the COM object(s)
if (WAIT_OBJECT0 != WaitForSingleObject(m_startupDone, ...))
{
   // handle failure like timeout
}
// By now all COM objects are guaranteed created and marshaled, unmarshall them all in main
// here must check if all threads actually succeeded (could be as simple as m_stream is not NULL)

// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));
m_startupDone=CreateEvent(NULL,FALSE,FALSE,NULL);
m_线程开始计数=
//启动线程
m_worker=boost::thread(&workerThread);
m_worker2=boost::thread(&workerThread);
...
//现在等待线程创建COM对象
if(WAIT_OBJECT0!=WaitForSingleObject(m_startupDone,…)
{
//处理诸如超时之类的故障
}
//到目前为止,所有COM对象都已保证创建和封送,并在主目录中全部解组
//这里必须检查所有线程是否真正成功(可以简单到m_stream不为NULL)
//获取接口代理
MyLib::IFooPtr foo;
LPVOID-vp(空);
HRESULT hr=cogetInterface和leaseStream(m_stream,foo.GetIID(),&vp);
如果(成功(hr))foo.Attach(静态施法(vp));

不,我不确定这是我想要的。我正在处理一个遗留的单线程应用程序,试图通过添加线程来缩短启动时间。我意识到我在用启动时间换取一般运行时间。我希望最终能将其提交给MTA,但使用STA作为开发的中间步骤。如果您启动了N个线程,每个线程创建一个STA对象,然后让每个线程在创建接口并将其封送到流中后,立即减少一个计数器(InterlocatedDecrement)。将其递减为0的是最后一个,可以发出事件信号。主线程处于空闲状态,等待一个this事件,当发出信号时,它可以安全地继续并解组所有流。这对传统应用程序逻辑的影响最小,同时允许并行创建N COM对象。您能举个例子吗?我不清楚如何使用
PostThreadMessage
MsgWaitForMultipleObjects