Это вполне может быть глупый вопрос, и если на этот вопрос уже был дан ответ в другом месте, я был бы очень признателен, если бы кто-то мог указать мне на это, поскольку мой поиск не дал ничего определенного.
В двух словах, моя проблема в том, что когда я выполняю childThread.Join () в потоке пользовательского интерфейса в дочернем потоке, который был помечен для остановки childThread, он блокируется так же, как и основной поток, поэтому все просто зависает.
То, что пользовательский интерфейс будет блокироваться из-за использования Join, в данный момент само по себе не является проблемой, поскольку childThread должен завершиться менее чем через секунду после того, как ему все равно будет приказано выйти.
Это происходит, когда я ожидаю завершения потока, выполняющего повторяющийся процесс, прежде чем я смогу запустить другой метод, который возвращает некоторую информацию, но не может быть запущен одновременно с другим процессом.
Приложение My Winforms интегрируется с частью USB-оборудования путем привязки C API к оборудованию.
В аппаратном API есть метод, который запускает процесс, который будет выполняться бесконечно, многократно и быстро, с обратным вызовом новой информации, которую мне затем нужно будет передать в пользовательский интерфейс.
Эта операция может быть отменена другим вызовом аппаратного API, который устанавливает флаг, который может видеть аппаратное обеспечение, чтобы оно могло выйти.
Я обернул этот API C своим собственным кодом C #, и внутри оболочки мне пришлось раскрутить вызов процесса запуска в другом потоке, чтобы действие не блокировало пользовательский интерфейс.
Вот отредактированные основные моменты того, что я делаю.
public class DeviceWrapper
{
Thread childThread = null;
void DeviceWrapper
{
//Set the callback to be used by the StartGettingInformation() process
PInvokeMethods.SetGetInformationCallback(InformationAcquiredCallback);
}
public void StartProcess()
{
childThread = new Thread(new ThreadStart(GetInformationProcess))
childThread.Start();
}
void GetInformationProcess()
{
PInvokeMethods.StartGettingInformation();
}
//This callback occurs inside the childThread
void InformationAcquiredCallback(Status status, IntPtr information)
{
//This callback is triggered when anything happens in the
//StartGettingInformation() method, such as when the information
//is ready to be retrieved, or when the process has been cancelled.
if(status == Status.InformationAcquired)
{
FireUpdateUIEvent();
}
//If the cancel flag has been set to true this will be hit.
else if(status == Status.Cancelled)
{
//Reset the cancel flag so the next operation works ok
PInvokeMethods.SetCancelFlag(false);
childThread.Abort();
}
}
//This method runs once, and can't run at the same time as GetInformationProcess
public string GetSpecificInformation()
{
//This triggers InformationAcquiredCallback with a status of Cancelled
StopProcess();
if(childThread.IsAlive)
{
childThread.Join();
}
return PInvokeMethods.GetSpecificInformation();
}
public void StopProcess()
{
PInvokeMethods.SetCancelFlag(true);
}
}
Используя этот код, когда я вызываю childThread.Join (), все приложение останавливается (что я ожидаю для пользовательского интерфейса, и это нормально), и childThread также, кажется, останавливается, потому что обратный вызов никогда не срабатывает снова.
Однако, если я вместо этого использую следующий код:
public string GetSpecificInformation()
{
//This triggers InformationAcquiredCallback with a status of Cancelled
StopProcess();
string s = "";
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
if(childThread.IsAlive)
{
childThread.Join();
}
s = PInvokeMethods.GetSpecificInformation();
}));
return s;
}
Затем все удаляется, как ожидалось, и childThread завершает работу, и все хорошо, за исключением того, что моя строка возвращается пустой до того, как WaitCallback сработает и присваивается ей.
Итак, мне просто нужно смириться с этим и изменить класс, чтобы я использовал QueueUserWorkItem и WaitCallback и вызвал событие для обработки моего возврата строки?
Есть ли что-то глупое, что я делаю в своем первом подходе, что также приводит к блокировке childThread?
Или есть какая-то другая тактика или класс, который я должен использовать целиком, учитывая, что у меня работает .NET 3.5?