Как передать указатель интерфейса на поток? - PullRequest
6 голосов
/ 04 февраля 2009

Примечание:

  • Использование raw Win32 CreateTheard () API
  • Нет MFC
  • Интерфейс - это просто указатель на vtable

Вопрос:

  • Как передать указатель на интерфейс в потоке?

Иллюстрация:

IS8Simulation *pis8 = NULL;

...

CoCreateInstance(
                 clsid,
                 NULL,
                 CLSCTX_LOCAL_SERVER,
                 __uuidof(IS8Simulation),
                 (void **) &pis8);



...

hThread = CreateThread(
                NULL,
                0,
                SecondaryThread,
                //interface pointer pis8
                0,
                &dwGenericThreadID);

...

DWORD WINAPI SecondaryThread(LPVOID iValue)
{
    //using iValue accordingly
    //E.g.: iValue->Open

Привет

Ответы [ 3 ]

8 голосов
/ 04 февраля 2009

Как было указано ниже, передача указателя интерфейса COM между потоками небезопасна.

Если вы знаете, что делаете:

hThread = CreateThread(
                NULL,
                        0,
                        SecondaryThread,
                        (LPVOID) pis8
                        0,
                        &dwGenericThreadID);

DWORD WINAPI SecondaryThread(LPVOID iValue)
{
   ((IS8Simulation*) iValue)->Open();
}

Потокобезопасная версия:

void MainThread()
{
    IStream* psis8;
    HRESULT res = CoMarshalInterThreadInterfaceInStream (IID_IS8SIMULATION, pis8, &psis8);
    if (FAILED(res))
         return;
    hThread = CreateThread(
                NULL,
                0,
                SecondaryThread,
                (LPVOID) psis8
                0,
                &dwGenericThreadID
          );
}

DWORD WINAPI SecondaryThread(LPVOID iValue)
{
   IS8Simulation* pis8;
   HRESULT res = CoGetInterfaceAndReleaseStream((IStream*) iValue, IID_IS8SIMULATION, &pis8);
   if (FAILED(res))
      return (DWORD) res;
   pis8->Open();
}
7 голосов
/ 04 февраля 2009

Если интерфейс в вашем вопросе является интерфейсом COM, подход, предложенный Quassnoi, может быть недостаточным. Вы должны обратить внимание на модель потоков используемого COM-объекта. Если вторичный поток присоединится к отдельной COM-квартире из той, в которой был создан ваш COM-объект, и если этот объект не является apartment-agile , вам потребуется маршалировать этот указатель интерфейса, чтобы вторичный поток получает прокси, а не прямой указатель на объект.

COM-объект обычно превращается в квартиру с помощью специальной реализации IMarshal. Самый простой подход состоит в агрегировании Free Threaded Marshaler.

Несколько полезных ссылок ...

Обновление: о маршалере со свободной резьбой ...

Из комментариев на эту тему видно, что некоторые люди рекомендуют никогда не трогать FTM. Хотя «Эффективный COM» - отличная книга, я думаю, что некоторые из ее рекомендаций открыты для толкования. Пункт 33 гласит: «Берегись FTM»; это не говорит "Никогда не используйте FTM". Очень мудро советует проявлять осторожность, особенно когда ваш объект, динамичный по квартире, содержит ссылки на другие объекты, потому что они могут не быть гибкими по квартире. Таким образом, на самом деле совет таков: тщательно продумайте, когда строите гибкие объекты, используют ли они FTM для достижения своей ловкости. Если вы уверены, что можете построить объект, способный к быстрым квартирам, я не вижу причин, по которым вы бы не использовали FTM для этого.

2 голосов
/ 04 февраля 2009

Вам необходимо сделать следующее:

  • CoMashalInterThreadInterfaceInStream ==> вы получаете интерфейс IStream.
  • передать этот поток IStream в поток, например, как сказал Кассной.
  • в SecondaryThread, вызовите CoGetInterfaceAndReleaseStream, чтобы получить интерфейс (или прокси-сервер к нему, если необходимо).

Не освобождайте интерфейс IStream, если не удается создать поток, и не выходите из потока, пока вы не вызовете CoGetInterfaceAndReleaseStream.

COM-среда автоматически создаст для вас прокси. Прокси-сервер гарантирует, что, например, COM-компонент с многопоточностью вызывается в потоке, который его создал. Однако для этого также необходимо, чтобы:

  • Интерфейс IDispatch, или для интерфейса зарегистрированы компоненты прокси / заглушки
  • поток, создавший компонент, имеет цикл обработки сообщений и обрабатывает сообщения
...