У меня есть собственное приложение C ++, вызывающее модуль C#, который должен запускать свою собственную программу l oop и передавать сообщения обратно в C ++ через предоставленный объект обратного вызова, используя COM. У меня есть приложение для работы, но у меня странная ошибка.
Перейти к самому концу для странного поведения и вопрос
Эти C# методы вызывается из C ++ через COM:
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("...")]
public interface IInterface
{
void Start(ICallback callback);
void Stop();
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("...")]
public interface ICallback
{
void Message(string message);
}
[Guid("...")]
public class MyInterface : IInterface
{
private Task task;
private CancellationTokenSource cancellation;
ICallback callback;
public void Start(ICallback callback)
{
Console.WriteLine("STARTING");
this.callback = callback;
this.cancellation = new CancellationTokenSource();
this.task = Task.Run(() => DoWork(), cancellation.Token);
Console.WriteLine("Service STARTED");
}
private void DoWork()
{
int i = 0;
while (!cancellation.IsCancellationRequested)
{
Task.Delay(1000, cancellation.Token).Wait();
Console.WriteLine("Starting iteration... {0}", i);
//callback.Message($"Message {0} reported");
Console.WriteLine("...Ending iteration {0}", i++);
}
Console.WriteLine("Service CANCELLED");
cancellation.Token.ThrowIfCancellationRequested();
}
public void Stop()
{
//cancellation.Cancel(); -- commented deliberately for testing
task.Wait();
}
В C ++ я предоставляю реализацию ICallback
, CCallback
:
#import "Interfaces.tlb" named_guids
class CCallback : public ICallback
{
public:
//! \brief Constructor
CCallback()
: m_nRef(0) { }
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
virtual HRESULT __stdcall raw_Message(BSTR message)
{
std::wstringstream ss;
ss << "Received: " << message;
wcout << ss.str() << endl;
return S_OK;
}
private:
long m_nRef;
};
Мой код вызова C ++ в основном:
CCallback callback;
IInterface *pInterface = GetInterface();
cout << "Hit Enter to start" << endl;
getch();
hr = pInterface->Start(&callback);
cout << "Hit Enter to stop" << endl;
getch();
pInterface->Stop();
cout << "Hit Enter to exit" << endl;
getch();
pInterface->Stop();
Это надуманный пример, позволяющий избежать публикации огромных кусков кода, но вы можете убедиться в том, что код C# должен равняться l oop раз в секунду, вызывая метод C ++, который печатает сообщение.
Если я оставлю эту строку с комментариями: //callback.Message($"Message reported at {System.DateTime.Now}");
она будет работать именно так, как можно себе представить. Если я раскомментирую , то произойдет:
CCallback callback;
IInterface *pInterface = GetInterface();
cout << "Hit Enter to start" << endl;
getch();
hr = pInterface->Start(&callback);
STARTING
Запуск итерации ... 0
cout << "Hit Enter to stop" << endl;
getch();
pInterface->Stop();
Получено: Сообщение 0 отправлено
... Завершающая итерация 0
Начальная итерация ... 1
Получено: Сообщение 1 отправлено
... Завершение итерации 1
(... и т. Д.)
cout << "Hit Enter to exit" << endl;
getch();
return;
Вывод
Так почему-то вызов callback.Message
останавливает мой Task
, пока не будет вызван Task.Wait
. С какой стати это будет? Как это застревает и как ожидание на задаче освобождает это? Я предполагаю, что модель потоков через COM означает, что у меня какая-то тупик, но кто-то может быть более конкретным? c?
Лично я считаю, что запускать все это в выделенном Thread
лучше, но это как существующий приложение работает, поэтому мне просто очень интересно, что происходит.
ОБНОВЛЕНИЕ
Итак, я проверил new Thread(DoWork).Start()
Vs Task.Run(()=>DoWork())
, и я получил точно такое же поведение - теперь он останавливается до тех пор, пока Stop
не вызовет Thread.Join
.
Так что я думаю, что COM по какой-то причине приостанавливает весь CLR или что-то в этом роде.