Формы и потоки

  • Автор темы Guest
  • Дата начала
G

Guest

#1
Хотел бы узнать по двум вопросам:

1. Как форме удаётся висеть, не пожирая ресурсов, и при этом не спать? То есть реагировать на все нажатия, перетаскивания и т.д..

2. Как можно в своём классе (не имеющего никакого отношения к System.Windows.Forms.Control) создать методы, аналогичный Control.Invoke и Control.BeginInvoke, которые гарантированно выполнялись бы в потоке объекта, даже если бы вызывались из других потоков?
 
M

mr_ST

#2
1) Она таки жрет ресурсы, но очень мало. Почитайте что такое очередь сообщений в win и как она работает.
2) В общем случае никак.
 

LuMee

Well-known member
02.05.2006
477
0
#3
2. Как можно в своём классе (не имеющего никакого отношения к System.Windows.Forms.Control) создать методы, аналогичный Control.Invoke и Control.BeginInvoke, которые гарантированно выполнялись бы в потоке объекта, даже если бы вызывались из других потоков?
Для начала неплохо бы определиться, что такое "поток объекта".
 
Y
#4
<!--QuoteBegin-Незнайка1965+-->
<span class="vbquote">(Незнайка1965)</span><!--QuoteEBegin-->которые гарантированно выполнялись бы в потоке объекта, даже если бы вызывались из других потоков?[/quote]А мне казалось, что в .Net все действия с объектами выполняются в потоке, в котором они были созданы... (кроме value-types, конечно)
 

LuMee

Well-known member
02.05.2006
477
0
#5
А мне казалось, что в .Net все действия с объектами выполняются в потоке, в котором они были созданы... (кроме value-types, конечно)
Почему так? Один объект вполне может использоваться несколькими потоками. Собственно, поэтому и существуют все эти хитромудрые механизмы синхронизации (мониторы, мьютексы и прочие другие).
 
G

Guest

#6
А мне казалось, что в .Net все действия с объектами выполняются в потоке, в котором они были созданы... (кроме value-types, конечно)
Не-а. Открытый метод какого-либо объекта в общем случае выполняется в том потоке, откуда его вызвали.
Собственно, для этого и нужны методы Conrtol.BeginInvoke, Control.Invoke.
 

LuMee

Well-known member
02.05.2006
477
0
#7
Можно попробовать такой финт ушами.
Завести некий класс-синглтон, инстанс которого будет содержать очередь делегатов и "вечный" поток, который будет доставать делегаты из очереди и вызывать на подконтрольных объектах.
Далее делаем некий базовый класс, в котором будет метод Invoke. Этот метод будет просто принимать делегат и класть его (и, м.б., какие-то дополнительные параметры) в вышеописанную очередь.
Далее все классы, которым нужен этот Invoke, наследуем от этого базового класса.
Таким образом, все действия, выполняемые через Invoke, будут всегда выполняться в одном и том же потоке. Можно также реализовать InvokeRequired: проверять, что текущий поток является тем самым "вечным" потоком синглтона.
 
Y
#8
да, ошибся.
А мне казалось, что в .Net все успешные действия с объектами (i.e. Control) могут выполнится только в потоке, в котором они были созданы... (кроме value-types, конечно)
Может вот такой вариант? сделать extention методы Get и Set для класса Control, которому будет передаватся свойство и значение и выполнятся в своем потоке. Что-то наподобие того, как сделано в WPF ?
 
G

Guest

#9
очередь делегатов и "вечный" поток, который будет доставать делегаты из очереди и вызывать на подконтрольных объектах.
Вечный поток делается с помощью бесконечного цикла с засыпанием (например, Thread.Sleep(100);), или есть другие средства?

И ещё, у меня была мысль из одной формы вызывать другую в отдельном потоке, но как только выполнялся конструктор этой самой другой формы, поток сразу заканчивался. Получалась парадоксальная ситуация: форма есть, а потока для неё - нет. Соответственно, когда во второй форме вызывался метод this.Invoke, выбрасывалось NullReferenceException.
Более-менее приемлемый выход такой:

secondForm=new SecondForm(...); // В самой форме будет this.Show();
while(!secondForm.IsDisposed)
{
Thread.Sleep(100);
}

, но предпочёл запускать вторую форму в отдельном процессе (думаю перевести на AppDomain).
 

LuMee

Well-known member
02.05.2006
477
0
#10
Вечный поток делается с помощью бесконечного цикла с засыпанием (например, Thread.Sleep(100):), или есть другие средства?
Да, думаю, такой подход подойдет. Получается такое тело цикла:
- читаем очередь делегатов и выполняем, пока не опустеет;
- как только очередь опустела, засыпаем на некоторое время.


Что касается форм, то создавать форму в отдельном потоке - неудачная затея, на мой взгляд. Лучше, чтобы весь UI был в одном потоке, а в другие потоки выностить уже какую-то рабочую логику (по мере выполнения которой можно обнолять UI).
 
G

Guest

#11
Да, думаю, такой подход подойдет. Получается такое тело цикла:
- читаем очередь делегатов и выполняем, пока не опустеет;
- как только очередь опустела, засыпаем на некоторое время.
Хорошо, а как сделать так, чтобы BeginInvoke выполнялся именно в этом потоке?
 

LuMee

Well-known member
02.05.2006
477
0
#12
Хорошо, а как сделать так, чтобы BeginInvoke выполнялся именно в этом потоке?
Не совсем понял вопрос. BeginInvoke сам по себе будет выполнен в том потоке, в котором будет вызван, однако его действия сведутся к добавлению делегата в вышеупомянутую очередь. Сам же делегат будет выполнен в специальном "делегатном" потоке, который обслуживает эту самую очередь.