2009-06-03 4 views
2

. Нечетная замкнутая семантика. Net снова прослушивает меня.C#: Подождите, пока переменная станет ненулевой.

Я запускаю нить, дочерняя нить по очереди запускает форму. Родительский поток должен ждать, пока форма не будет создана.

Моя первая попытка была использовать монитор для просмотра переменной формы:

private void OpenForm() 
{ 
    if (FormThread == null) 
    { 
     Monitor.Enter(Form); 
     FormThread = new Thread(FormStub); 
     FormThread.SetApartmentState(ApartmentState.STA); 
     FormThread.Start(); 
     Monitor.Wait(Form); 
     Monitor.Exit(Form); 
    } 
} 

private void FormStub() 
{ 
    Form = new ConnectorForm(); 
    Monitor.Enter(Form); 
    Monitor.PulseAll(Form); 
    Monitor.Exit(Form); 
    Application.Run(Form); 
} 

... Это вызывает исключение. Ошибка Monitor.Enter(), так как Form == null.

Я мог бы легко создать фиктивное целое или что-то в этом роде (на самом деле я думаю, что я смогу обработать переменную FormThread), но мне было интересно, было ли более элегантное решение.

ответ

4

Лучше примитив синхронизация для этого случая:

private ManualResetEvent mre = new ManualResetEvent(false); 

private void OpenForm() 
{ 
    if (FormThread == null) 
    { 
     FormThread = new Thread(FormStub); 
     FormThread.SetApartmentState(ApartmentState.STA); 
     FormThread.Start(); 
     mre.WaitOne(); 
    } 
} 

private void FormStub() 
{ 
    Form = new ConnectorForm(); 
    mre.Set(); 
    Application.Run(Form); 
} 
+0

Это кажется быть именно примитивным, которого я искал. Я пропустил это, когда прочитал список вещей в System.Threading, по-видимому ... мои глазные яблоки искали «Событие» или что-то в этом роде. – Thanatos

0

Не выполняет ли спин-ожидание текущей нити, удаляя всю точку использования отдельного потока, чтобы помешать новой форме? Если я что-то не понимаю, вы просто хотите создать новую форму синхронно. (Есть ли какой-либо причине он должен находиться в другом ГНА?)

+0

Похоже, что он хочет, чтобы запустить его основной цикл приложения от другого нить почему-то ...? – jerryjvl

+0

Небольшая проблема заключается в том, что она позволяет мне не беспокоиться о моделировании потоков в основном потоке и поддерживает ли она формы. Большим преимуществом является то, что основной поток получает контроль, возвращенный ему, и может выполнять операции, как если бы он был однопоточным, в то время как эта форма сидит в другом потоке и позволяет пользователю развлекаться и информироваться. Я надеюсь, что конечный API для основного потока очень приятный. – Thanatos

0

Вы можете попробовать следующее, который использует один object/Monitor как механизм сообщения:

private void OpenForm() 
{ 
    if (FormThread == null) 
    { 
     object obj = new object(); 
     lock (obj) 
     { 
      FormThread = new Thread(delegate() { 
       lock (obj) 
       { 
        Form = new ControllerForm(); 
        Monitor.Pulse(obj); 
       } 
       Application.Run(Form); 
      }); 
      FormThread.SetApartmentState(ApartmentState.STA); 
      FormThread.Start(); 
      Monitor.Wait(obj); 
     } 
    } 
} 

Исходный поток удерживает блокировку пока он не наберет Monitor.Wait; это позволяет второй поток (уже начатый) в создании формы, импульс исходной нити обратно в жизнь и освобождение; исходная нить затем выходит только после того, как Form существует.

+0

Что происходит, если 'Monitor.Pulse' вызывается между' FromThread.Start' и 'Monitor.Wait'? – Dialecticus

+0

@Dialecticus помните: единственным человеком, который может называть 'Pulse', является человек, у которого есть замок. И пока вы не назовете 'Wait', эта блокировка используется. Поэтому ответ на это либо «не может быть», либо более явно: «поток, который вызывает« Monitor.Pulse », получит исключение, потому что * у них нет блокировки *« –

0

Я предпочитаю использовать AutoResetEvent для подобных случаев:

private AutoResetEvent _waitHandle = new AutoResetEvent(false); 

private void OpenForm() 
{ 
    Thread formThread = new Thread(FormStub); 
    formThread.SetApartmentState(ApartmentState.STA); 
    formThread.Start(); 
    _waitHandle.WaitOne(); 

    // when you come here FormStub has signaled     
} 

private void FormStub() 
{ 
    // do the work 

    // signal that we are done 
    _waitHandle.Set(); 
} 
-1

Использование статического BOOL для флага или не загрузится форма. Это атомный, поэтому не нужно блокировать.

В основном коде просто сделать что-то вроде

while(!formRun) { Thread.Sleep(100); } 

Реальный вопрос, почему вы это делаете? Обычно вы хотите, чтобы основной поток запускал GUI-файл, а вторичные потоки - для запуска вспомогательного кода. Если вы объясните, зачем вам это нужно, мы можем придумать лучшую технику.

+0

Лучшая надежда, что formRun является изменчивым, тогда .. это не гарантирует когда-либо выйти иначе. –

0

Другой способ передать EventWaitHandle, чтобы передать его в FormStub в качестве параметра (так что не загромождать модель объекта):

static void Main() 
{ 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 

    EventWaitHandle e = new EventWaitHandle(false, EventResetMode.ManualReset); 
    Thread t = new Thread(FormStub); 
    t.SetApartmentState(ApartmentState.STA); 
    t.Start(e); 
    e.WaitOne(); 
} 

static void FormStub(object param) 
{ 
    EventWaitHandle e = (EventWaitHandle) param; 
    Form f = new Form1(); 

    e.Set(); 
    Application.Run(new Form1()); 
} 
Смежные вопросы