Резьбонарезной таймер в C#
Как я могу запустить timer1_Tick в отдельном потоке ?
Я искал везде в google и ничего не нашел.
Вы ничего не нашли просто потому, что нет ничего особенного в таймере и потоке. Как вы думаете, если бы вы спросили "как найти подстроку в отдельном потоке" или "как написать файл в отдельном потоке", вы бы нашли окончательный ответ? Нет. Потому что не важно, какая нить. А что такое "отдельный"? Отдельно от чего?
Может быть и другая причина: нет такого события "timer1_Tick". Это просто имя метода, оно может быть любым.
Есть по крайней мере три разных таймера: System.Threading.Timer
, System.Timers.Timer
и System.Windows.Forms.Timer
Я перечислил их в порядке, грубо говоря, от низко-рычажного до высокоуровневого. Fist timer не имеет событий, только обратный вызов, который является делегатом. Второй таймер имеет события Disposed
и Elapsed
, и третий таймер должен произойти Tick
Итак, ваш вопрос, скорее всего, касается System.Windows.Forms.Timer
Как использовать его в "отдельном" потоке? Поскольку этот таймер "принадлежит" пользовательскому интерфейсу Forms, "отдельный", вероятно, должен означать "из потока, отличного от потока пользовательского интерфейса".
Короткий ответ: Не используйте его, даже "из" потока пользовательского интерфейса. Этот таймер печально известен своей неточностью. Используйте его, но только в потоке пользовательского интерфейса (вы можете сделать это в потоке без пользовательского интерфейса с некоторыми предосторожностями (см. ниже), но в этом случае вы теряете его единственное преимущество-надежную простоту). Итак, если вы плохо понимаете поток, механизм вызова (см. ниже) и не заботитесь о точности (на самом деле не заботитесь, потому что то, что вы получаете, может быть удивительно плохим), вы можете использовать его. Вы должны управлять этим таймером в потоке пользовательского интерфейса, но в обработчике его Tick
метод вы также можете использовать его в предположении, что это тот же поток пользовательского интерфейса, поэтому вы можете вызывать методы и свойства пользовательского интерфейса.
Если вам нужно какое-то качество, используйте любой из других таймеров. Однако в обратном вызове или обработчике событий вы не можете вызывать какие-либо методы и свойства. Вы можете вызвать их косвенно из потока пользовательского интерфейса, используя механизм вызова потока пользовательского интерфейса. Вам нужно будет использовать метод Invoke
или BeginInvoke
из класса System.Threading.Dispatcher
(WPF или формы) или System.Windows.Forms.Control
(естественно, только для форм; вы можете использовать любой экземпляр элемента управления, участвующий в текущем запуске Application
).
Подробное объяснение механизма вызова и примеров кода см. В моих прошлых ответах:
Контроль.Invoke () против Control.BeginInvoke()[^],
Проблема со сканером Treeview и MD5[^].
Тем не менее, с этими двумя таймерами не имеет значения, в каком потоке они используются.
Это приводит к окончательной идее: не используйте никаких таймеров вообще, если вы можете использовать вместо них потоки. С таймерами вы получите гораздо больше неприятностей. Вы даже пытались разработать программное обеспечение с учетом следующей возможности: что делать, если следующее событие таймера срабатывает, когда обработка в обработчике, вызванная предыдущим событием, еще не завершена? Это всего лишь намек. С нитями таких проблем нет.
Пожалуйста, посмотрите мои прошлые ответы на эту тему:
Как получить событие keydown для того чтобы работать в другом потоке, в vb.net[^],
Контроль событий, не срабатывающих после включения отключения + многопоточности[^].
Хорошее объяснение. проголосовали 5.
Я бы сказал, что нет... пока.
Спасибо.
--СА
5+!
Спасибо, Сандип.
--СА
Короче говоря - как указал Сакрюков, не используйте System.Windows.Forms.Timer
если вы хотите Tick
обработчик в отдельном потоке-он предназначен специально для вызова потока пользовательского интерфейса.
Вместо этого используйте System.Timers.Timer
и это Elapsed
событие, которое будет вызвано в потоке таймера, автоматически выделяется (не UI).
Предоставляет механизм для выполнения метода с заданными интервалами. Этот класс не может быть унаследован.
иерархия наследования
Система.Объект
Системы.Класса MarshalByRefObject
Система.Нарезание резьбы.Таймер
Пространство Имен: System.Нарезание резьбы
Сборка: mscorlib (in mscorlib.dll)
Синтаксис
С#
С++
Ф#
ГЛ.
[ComVisibleAttribute (true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, синхронизация = true,
ExternalThreading = истина)]
таймер открытого запечатанного класса: MarshalByRefObject,
IDisposable
Тип таймера предоставляет следующие элементы.
Проектировщики
Название Описание
Таймер открытого метода (TimerCallback) Инициализирует новый экземпляр класса Timer с бесконечным периодом и бесконечным временем выполнения, используя вновь созданный объект Timer в качестве объекта состояния.
Открытый метод поддерживается платформой XNA на поддерживаемых портативных таймер библиотеки классов(TimerCallback, объект типа int32, int32 отсчитываемый) Инициализирует новый экземпляр класса Timer, используя 32-разрядное целое число со знаком для указания временного интервала.
Открытый метод, поддерживаемый таймером XNA Framework (TimerCallback, Object, Int64, Int64) Инициализирует новый экземпляр класса Timer, используя 64-битные целые числа со знаком для измерения временных интервалов.
Открытый метод поддерживается платформой XNA на поддерживаемых портативных таймер библиотеки классов(TimerCallback, объект, период, промежуток времени) инициализирует новый экземпляр класса timer, используя значения TimeSpan для измерения временных интервалов.
Открытый метод, поддерживаемый таймером XNA Framework (TimerCallback, Object, UInt32, UInt32) Инициализирует новый экземпляр класса Timer, используя 32-разрядные целые числа без знака для измерения временных интервалов.
Верхний
Методы
Название Описание
Открытый метод поддерживается платформой XNA на поддерживаемых портативных изменения библиотеки классов(типа int32, int32 отсчитываемый) Изменяет время начала и интервал между вызовами метода для таймера, используя 32-битные целые числа со знаком для измерения временных интервалов.
Открытый метод, поддерживаемый изменением фреймворка XNA (Int64, Int64) Изменяет время начала и интервал между вызовами метода для таймера, используя 64-битные целые числа со знаком для измерения временных интервалов.
Открытый метод поддерживается платформой XNA на поддерживаемых портативных изменения библиотеки классов(промежуток, интервал) меняет время запуска и интервал между вызовами метода таймера, используя значения TimeSpan для измерения временных интервалов.
Открытый метод, поддерживаемый изменением фреймворка XNA (UInt32, UInt32) Изменяет время начала и интервал между вызовами метода для таймера, используя 32-битные целые числа без знака для измерения временных интервалов.
Открытый метод CreateObjRef создает объект, содержащий всю необходимую информацию, необходимую для создания прокси-сервера, используемого для связи с удаленным объектом. (Наследуется от MarshalByRefObject.)
Открытый метод, поддерживаемый платформой XNA, поддерживаемой портативной библиотекой классов Dispose, освобождает все ресурсы, используемые текущим экземпляром Timer.
Открытый метод Dispose (WaitHandle) освобождает все ресурсы, используемые текущим экземпляром Timer, и сигнализирует, когда таймер был удален.
Открытый метод, поддерживаемый платформой XNA, поддерживаемой Portable Class Library Equals (Object), определяет, равен ли указанный объект текущему объекту. (Наследуется от объекта.)
Защищенный метод, поддерживаемый фреймворком XNA, поддерживаемым Portable Class Library Finalize, позволяет объекту попытаться освободить ресурсы и выполнить другие операции очистки до того, как он будет восстановлен сборкой мусора. (Наследуется от объекта.)
Публичный метод, поддерживаемый фреймворком XNA, поддерживаемым портативной библиотекой классов GetHashCode, служит хэш-функцией для определенного типа. (Наследуется от объекта.)
GetLifetimeService публичный метод возвращает текущий объект эксплуатации, который управляет политикой времени существования данного экземпляра. (Наследуется от MarshalByRefObject.)
Открытый метод, поддерживаемый платформой XNA, поддерживаемой портативной библиотекой классов GetType, получает тип текущего экземпляра. (Наследуется от объекта.)
InitializeLifetimeService открытый метод получает срок службы объекта управления политикой времени существования данного экземпляра. (Наследуется от MarshalByRefObject.)
Защищенный метод поддерживается платформой XNA на поддерживается переносимая библиотека классов MemberwiseClone создает неполную копию текущего объекта. (Наследуется от объекта.)
Защищенный метод MemberwiseClone(Boolean) Создает неглубокую копию текущего объекта MarshalByRefObject. (Наследуется от MarshalByRefObject.)
Открытый метод, поддерживаемый платформой XNA, поддерживаемой переносимой библиотекой классов ToString, возвращает строку, представляющую текущий объект. (Наследуется от объекта.)
Верхний
Замечания
Использование делегата TimerCallback, чтобы определить метод, который вы хотите, чтобы таймер выполняет. Делегат таймера задается при построении таймера и не может быть изменен. Метод не выполняется в потоке, создавшем таймер; он выполняется в потоке ThreadPool, поставляемом системой.
При создании таймера можно указать время ожидания до первого выполнения метода (due time) и время ожидания между последующими исполнениями (period). Вы можете изменить эти значения или отключить таймер, используя метод Change.
Примечание
Пока вы используете таймер, вы должны держать ссылку на него. Как и любой управляемый объект, таймер подвергается сборке мусора, когда на него нет ссылок. Тот факт, что таймер все еще активен, не мешает его сбору.
Когда таймер больше не нужен, используйте метод Dispose, чтобы освободить ресурсы, удерживаемые таймером. Обратите внимание,что обратные вызовы могут возникать после вызова перегрузки метода Dispose, поскольку таймер ставит обратные вызовы в очередь для выполнения потоками пула потоков. Вы можете использовать перегрузку метода Dispose(WaitHandle), чтобы дождаться завершения всех обратных вызовов.
Метод обратного вызова, выполняемый таймером, должен быть реентерабельным, поскольку он вызывается в потоках ThreadPool. Обратный вызов может быть выполнен одновременно в двух потоках пула потоков, если интервал таймера меньше времени, необходимого для выполнения обратного вызова, или если используются все потоки пула потоков и обратный вызов ставится в очередь несколько раз.
Примечание
Система.Нарезание резьбы.Таймер-это простой, легкий таймер, который использует методы обратного вызова и обслуживается потоками пула потоков. Он не рекомендуется использовать с Windows Forms, поскольку его обратные вызовы не происходят в потоке пользовательского интерфейса. Система.Окна.Формы.Таймер-это лучший выбор для использования с Windows Forms. Для серверной функции таймера вы можете рассмотреть возможность использования System.Таймеры.Таймер, который вызывает события и имеет дополнительные функции.
Примечание
Атрибут HostProtectionAttribute, применяемый к этому типу или члену, имеет следующее значение свойства Resources: Synchronization | ExternalThreading. Атрибут HostProtectionAttribute не влияет на настольные приложения (которые обычно запускаются двойным щелчком по значку, вводом команды или вводом URL-адреса в браузере). Дополнительные сведения см. В разделе класс HostProtectionAttribute или атрибуты программирования SQL Server и защиты Хоста.
Примеры
В следующем примере кода демонстрируются возможности класса Timer.
С#
С++
ГЛ.
using System; using System.Threading; class TimerExample { static void Main() { // Create an event to signal the timeout count threshold in the // timer callback. AutoResetEvent autoEvent = new AutoResetEvent(false); StatusChecker statusChecker = new StatusChecker(10); // Create an inferred delegate that invokes methods for the timer. TimerCallback tcb = statusChecker.CheckStatus; // Create a timer that signals the delegate to invoke // CheckStatus after one second, and every 1/4 second // thereafter. Console.WriteLine("{0} Creating timer.\n", DateTime.Now.ToString("h:mm:ss.fff")); Timer stateTimer = new Timer(tcb, autoEvent, 1000, 250); // When autoEvent signals, change the period to every // 1/2 second. autoEvent.WaitOne(5000, false); stateTimer.Change(0, 500); Console.WriteLine("\nChanging period.\n"); // When autoEvent signals the second time, dispose of // the timer. autoEvent.WaitOne(5000, false); stateTimer.Dispose(); Console.WriteLine("\nDestroying timer."); } } class StatusChecker { private int invokeCount; private int maxCount; public StatusChecker(int count) { invokeCount = 0; maxCount = count; } // This method is called by the timer delegate. public void CheckStatus(Object stateInfo) { AutoResetEvent autoEvent = (AutoResetEvent)stateInfo; Console.WriteLine("{0} Checking status {1,2}.", DateTime.Now.ToString("h:mm:ss.fff"), (++invokeCount).ToString()); if(invokeCount == maxCount) { // Reset the counter and signal Main. invokeCount = 0; autoEvent.Set(); } } }
Это был не таймер с резьбой. Это таймер с продевать нитку:
using System; using System.ServiceProcess; using System.Threading; using System.Timers; namespace MyNamespace { public partial class Service1: ServiceBase { Thread syncThread = null; System.Timers.Timer timer1; public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { timer1 = new System.Timers.Timer(); timer1.Interval = 60000; // 1 min timer1.Enabled = true; timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed); timer1.Start(); } protected override void OnStop() { syncThread.Abort(); timer1.Stop(); } protected void timer1_Elapsed(object sender, ElapsedEventArgs e) { syncThread = new Thread(new ThreadStart(doStuffInMyOwnThread)); syncThread.Start(); } protected void doStuffInMyOwnThread() { // whatever you put here, it will // run for each timer interval that elapses // in a separate thread, and each thread will // end when the processing in this function ends } } }
Всего на 5 лет опоздал.