Как запустить бесконечный цикл без зависания программы? (С#)

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

Этот цикл необходим и пока не может быть изменен.

Есть ли способ запустить этот цикл как «фоновый» и по-прежнему использовать другие параметры в программе, а именно: что цикл не блокирует процесс (я не хотел бы использовать потоки внутри потоков!).

Main Program
     |
     -------Thread(Function)
                       |
                       --------In the function ANOTHER
                               function is called with 
                               an infinite loop inside 
                               (this loop is NOT part of the 
                                Thread function directly)     

EDIT: добавлен пример кода:

//Here I call the threads
private void userTest_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < numberOfDevices; i++)
        {
            try
            {
            Thread t = new Thread(unused => device(i, sender, e));
            t.IsBackground = true;
            t.Start();
            }
            catch (ThreadStateException f)
            {
                MessageBox.Show("ERROR:" + f);  // Display text of exception
            }
         }
      }

Функция потока:

    //This infinite loop is useless, so it could be deleted. This is not
    // the loop I´m talking about
    public void device(object i, object s, object f)
    {
        while (true)
        {
            if (!killEm)
            {
                int j = (int)i;
                EventArgs g = (EventArgs)f;
                BSSDK.BS_SetDeviceID(m_ConnectedDeviceHandle[j],
                 m_ConnectedDeviceID[j], m_ConnectedDeviceType[j]);

                UserManagement userTest = new UserManagement();


                userTest.SetDevice(m_ConnectedDeviceHandle[j],
                    m_ConnectedDeviceID[j], m_ConnectedDeviceType[j]);
                userTest.ShowDialog();

            }
            else
            {
                userTest.Dispose();
                MessageBox.Show("Why don´t u kill it!!?");
                break;
            }
        }
    }

В функции userTest.ShowDialog() находится бесконечный цикл, о котором я говорю.

EDIT Это часть функции, которая вызывается в userTest.ShowDialog().

private void user_Click(object sender, EventArgs e) {

//THIS IS THE LOOP I´M TALKING!
while (true) {
    Keep listening for an user put his finger in the device
    ...
    Do things with that finger template
    ...   
}

}

Спасибо.


person Kani    schedule 04.11.2011    source источник
comment
Пожалуйста, покажите нам свой код; если вы правильно используете потоки, этого не произойдет.   -  person SLaks    schedule 04.11.2011
comment
Вам нужно запустить поток асинхронно.   -  person MGZero    schedule 04.11.2011
comment
Итак, позвольте мне понять: вы открываете новое окно в новом потоке и запускаете бесконечный цикл внутри этого нового окна?   -  person Toomai    schedule 04.11.2011
comment
@Toomai: да, именно это я и делаю   -  person Kani    schedule 04.11.2011
comment
Что делается внутри бесконечного цикла?   -  person user957902    schedule 04.11.2011
comment
@user957902: Я постоянно запускаю функции биометрического устройства для отпечатков пальцев, поэтому можно идентифицировать пользователя, когда он прикладывает палец. Должен слушать (зацикливать) все время.   -  person Kani    schedule 04.11.2011
comment
Я не знаю точной разницы между Java и C# в отношении потоков, но если вы поместите не спящий бесконечный цикл в метод запуска Java-Thread, вы заблокируете этот процесс. В Java даже вызов sleep(10) предотвратит блокировку — не поможет ли это в данной ситуации?   -  person Brandon Buck    schedule 04.11.2011
comment
Ну, поток не заблокирован, что заблокировано в бесконечном цикле, который я использую в другой функции, которую я вызываю в процессе потока. Сам поток работает нормально.   -  person Kani    schedule 04.11.2011
comment
@Kani Кажется, вы не понимаете точного значения таких терминов, как поток, процесс, цикл, функция и блокировка.   -  person Andrew Barber    schedule 04.11.2011
comment
Грубо говоря: поток выполняет процесс. Потоки могут использовать блокировки для синхронизации. Я использую термин блокировка в своем вопросе не в контексте потока, а в цикле, просто для того, чтобы сказать, что программа зависает. Возможно, я злоупотреблял обозначениями (изменил название поста, блокировка формы на зависание, если поможет).   -  person Kani    schedule 04.11.2011
comment
@ Кани ошибается, ошибается, ошибается. процессы содержат потоки. потоки не выполняют процессы. (хотя код, работающий в потоке, может порождать другой процесс... это, безусловно, не то, что здесь происходит...)   -  person Andrew Barber    schedule 04.11.2011


Ответы (5)


Хорошо; Вот хорошая новость: вам вообще не нужны потоки. По сути, здесь у вас есть обычный компонент Windows Forms в виде «форм». Эти формы должны оставаться «активными», чтобы реагировать на события. Однако для этого не нужно создавать потоки.

Ключом является статический класс System.Windows.Forms.Application, в котором есть функция, созданная специально для того, что вам здесь нужно.

System.Windows.Forms.Application.Run();

Этот метод позволяет вашим объектам Form работать, реагируя на события, не позволяя функции, которую он вызывает, продолжать работу. Он «блокирует», позволяя потоку сообщений отвечать, пока не будет вызван Application.Exit() или некоторые другие подобные методы.

Что вы хотите сделать в вашем случае, так это создать все ваши формы и вызвать Show() для каждой из них по очереди (не ShowDialog()), а затем, наконец, вызвать Application.Run(). Это дает вам то, что вы хотите.

Чтобы завершить вашу программу, вам нужно где-то вызвать Application.Exit() в ответ на что-то. У вас есть два варианта, которые быстро сработают для вас:

  • Создайте отдельную «форму управления», которая представляет собой простую форму, которая при закрытии вызывает Application.Exit(), возможно, после циклического просмотра всех ваших форм управления пользователями и закрытия их в первую очередь. Вы можете сделать это, например, с помощью события Form.OnClosing формы управления.
  • Добавьте событие к каждому из событий Form.OnClosing форм userManagement, которое проверяет, когда последнее закрыто (или, возможно, закрыто ли какое-либо из них?), и, как и выше, вызовите там Application.Exit().

Как только вы вызываете Application.Exit(), все открытые формы должны быть удалены (сначала я рекомендую сделать это вручную...), а затем ваш вызов в основном потоке к Application.Run() завершится, позволяя вашей программе продолжить... мы предполагаем, чтобы закончить .


РЕДАКТИРОВАТЬ: Старый ответ, для потомков...

Вы создаете новую тему не в том месте.

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

В идеале, этот цикл должен иметь возможность изящно отмениться, но вы, кажется, предполагаете, что не можете трогать этот код...

person Andrew Barber    schedule 04.11.2011
comment
Ну, причина, по которой я создаю поток для второго окна, заключается в том, что это окно представляет устройство, а у меня должно быть столько потоков, сколько устройств. Они должны работать одновременно. Что вы имеете в виду под созданием потока для долговременной задачи? В этом случае, что это будет? (Извините, мой опыт работы с потоками очень скуден) - person Kani; 04.11.2011
comment
@Kani Хорошо, я только что просмотрел код, который вы разместили, и у меня есть вопрос или два ... UserTest - это объект формы, который находится в SDK, который вы используете, и это то, что вам нужно, чтобы продолжать работать, и что вы нельзя изменить? - person Andrew Barber; 04.11.2011
comment
ЭндрюБарбер: невозможно изменить цикл while в user_Click, который является функцией, вызываемой продуктом userTest.ShowDialog(). Эта функция имеет цикл, о котором я говорю. Потоки здесь ничего не делают — проблема была бы той же без потоков — я просто говорил, что эта функция вызывается потоком. - person Kani; 04.11.2011
comment
@Kani Хорошо, я думаю, что во всем разобрался. Я собираюсь отредактировать свой ответ и отвечу еще раз, чтобы сообщить вам, когда это будет сделано. - person Andrew Barber; 04.11.2011
comment
@Kani Хорошо; Я отредактировал свой ответ для того, что, по моему мнению, происходит. Дайте мне знать, что вы думаете. - person Andrew Barber; 04.11.2011
comment
Спасибо! Попробую реализовать, посмотрим на результат. Я выложу результаты как можно скорее. - person Kani; 04.11.2011

Вы должны избегать циклов занятости, почему вы не можете зацикливаться на каком-то спящем или приостанавливающемся системном вызове?

person Basile Starynkevitch    schedule 04.11.2011

Помимо того факта, хорошая это идея или нет, вы пробовали BackgroundWorker?

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=VS.80).aspx

person Remy    schedule 04.11.2011
comment
Ну, даже если я использую BackgroundWorker, бесконечный цикл будет блокироваться — насколько я понял документацию — потому что у меня нет возможности сегментировать эту часть кода. Ну, я мог бы поставить это функцию и попробовать. Позвольте мне попробовать. - person Kani; 04.11.2011

Вы можете создать новый поток http://msdn.microsoft.com/en-us/library/aa645740%28v=vs.71%29.aspx

or

Возможно, было бы уместно использовать таймер http://msdn.microsoft.com/en-us/library/system.timers.timer%28v=vs.71%29.aspx

person Matthew    schedule 04.11.2011
comment
ничего себе, если бы я использовал потоки внутри потоков, логика программы была бы затемнена еще больше. Я хотел бы избежать этого, если это возможно. Хотя, если по вашему опыту это стандартный способ решения, я мог бы попробовать! - person Kani; 04.11.2011
comment
@Kani На самом деле нет такой вещи, как потоки внутри потоков. Откуда вы взяли эту идею? - person Andrew Barber; 04.11.2011
comment
Извините, я пытался сказать, что по логике программы я бы вызывал поток и в процессе этого потока я вызывал бы другой. Конечно, нить есть нить. Но если я затуманю логику программы то будет очень сложно поддерживать в и без того сложной программе про биометрию :/ - person Kani; 04.11.2011

Это не имеет ничего общего с потоками — даже если вы вызовете эту «функцию бесконечного цикла» из основного потока, она все равно повесит вашу программу.

Итак, кто бы ни был автором этой функции, он/она должен был внедрить какой-то механизм для ее остановки, иначе она была бы совершенно бесполезна. Если не считать принудительного уничтожения потока (Thread.Abort), я предлагаю изучить этот механизм и использовать его в своем потоке.

Кстати, какова цель этой функции? Какая-то обработка сообщений?

--- ИЗМЕНИТЬ ---

Итак, ваш «бесконечный цикл» на самом деле Form.ShowDialog. Внутри он содержит насос сообщений, и способ программно остановить этот насос состоит в том, чтобы установить Form.DialogResult. Обратите внимание, что вам необходимо маршалировать все вызовы пользовательского интерфейса в соответствующие потоки, как указано в этом сообщение.

Кроме того, попробуйте запустить форму через Application.Run(Form), вместо Form.ShowDialog.

person Branko Dimitrijevic    schedule 04.11.2011
comment
Я постоянно запускаю функции биометрического устройства по отпечаткам пальцев, чтобы можно было идентифицировать пользователя, когда он прикладывает палец. Должен слушать (зацикливать) все время. Я реализовал бесконечный цикл, но не нашел другого способа заставить устройство постоянно слушать :/ - person Kani; 04.11.2011
comment
@Kani Тот факт, что у вас есть цикл, не имеет ничего общего с бесконечностью этого цикла. Есть несколько способов остановить такой цикл: от простых, таких как установка флага bool, который проверяется самим циклом, до более сложных, таких как отмена задачи TPL. В вашем случае вы эффективно передадите сообщение о закрытии диалогового окна в насос сообщения диалога (см. редактирование). - person Branko Dimitrijevic; 04.11.2011
comment
дело в том, что цикл должен никогда останавливаться. Даже во время производства он должен работать постоянно 24/7. Я не хочу останавливать цикл, мне нужно использовать цикл, но без блокировки программы. Возможно, это невозможно из-за внутренней природы бесконечных циклов - глючит-. (Спасибо за подсказку о DialogResult, я буду использовать в другой части кода. Это более элегантно) - person Kani; 04.11.2011
comment
@ Кани багги? Если вы имеете в виду свой код... вы, кажется, пытаетесь сделать это всеми возможными способами, но правильно. - person Andrew Barber; 04.11.2011
comment
@Kani Возможно, я не правильно понял ваш вопрос - вы говорите, что ShowDialog закрывает основной поток даже при вызове из другого потока? Если да, попробуйте Application.Run и посмотрите, изменится ли что-нибудь. Вы можете взглянуть на: stackoverflow.com /questions/1566791/run-multiple-ui-threads/ - person Branko Dimitrijevic; 04.11.2011
comment
@AndrewBarber: да, я знаю, что мой код содержит ошибки, а бесконечный цикл совершенно неверен. Но это единственный способ, который у меня есть на данный момент. Я использую эти устройства, а SDK ограничен и не содержит документации. Я не нашел другого решения, ребята из устройств не дают мне ответа, и мне нужно решить программирование с помощью биометрии. - person Kani; 04.11.2011
comment
@Kani Есть ли конкретная причина для вызова ShowDialog вместо просто Show (и обработки всего в основном потоке пользовательского интерфейса)? - person Branko Dimitrijevic; 04.11.2011
comment
@BrankoDimitrijevic: Может быть, я переписал вопрос. По сути, у меня есть бесконечный цикл — давайте забудем, что есть потоки — который блокирует мою программу. Я не хочу, чтобы программа была заблокирована. Поток, который я использую, вызывает функцию, которая, кстати, имеет цикл, который не блокирует поток с точки зрения выполнения. Он выполняется, но я не могу использовать какие-либо параметры этой формы Windows — той, что в потоке — из-за цикла. Обратите внимание, что поток выполняется - person Kani; 04.11.2011
comment
@BrankoDimitrijevic: да, есть причина, используя ShowDialog will stop the thread from ending until the window is dismissed - person Kani; 04.11.2011
comment
@Kani Я не знаю, откуда вы взяли свои идеи о том, как работает многопоточность, и я не знаю, насколько проблематична неточная природа вашего использования терминов (потоки не вызывают функции ... они их выполняют )... но я не вижу, чтобы это куда-то шло. - person Andrew Barber; 04.11.2011