которая неизвестно сколько будет выполняться. Мне нужно чтобы при следующем тике таймера проверялось, закончился ли асинхронный запрос и если нет, то не вызывать эту функцию (DiscoverDevice). Можно конечно сделать глобальную переменную и проверять, но как сделать правильно?
Здравствуйте, Аноним, Вы писали:
А>которая неизвестно сколько будет выполняться. Мне нужно чтобы при следующем тике таймера проверялось, закончился ли асинхронный запрос и если нет, то не вызывать эту функцию (DiscoverDevice). Можно конечно сделать глобальную переменную и проверять, но как сделать правильно?
Если красиво — то написать функцию, которая принимает на вход функцию и возвращает функцию, которая будучи вызвана, вызывает переданную функцию только в том случае, если функция уже закончила работу. И в обработчике таймера дергать это функцию.
Здравствуйте, Lloyd, Вы писали:
L>Если красиво — то написать функцию, которая принимает на вход функцию и возвращает функцию, которая будучи вызвана, вызывает переданную функцию только в том случае, если функция уже закончила работу. И в обработчике таймера дергать это функцию.
L>Надеюсь, понятно объяснил?
Как-то так:
using System;
using System.Threading;
class Program
{
private static readonly Action<int> PrintOnceInTime = FunctionalHelpers.OnceInTime<int>(Print);
private static void Print(int i)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
static void Main()
{
for (int i = 0; i < 10000; i++)
{
PrintOnceInTime.BeginInvoke(i, null, null);
Thread.Sleep(250);
}
}
}
public static class FunctionalHelpers
{
public static Action<T> OnceInTime<T>(Action<T> action)
{
bool isRuning = false;
return t =>
{
if (isRuning)
return;
try
{
isRuning = true;
action(t);
}
finally
{
isRuning = false;
}
};
}
}
Здравствуйте, Аноним, Вы писали:
А>на форме есть таймер (System.Windows.Forms.Timer), он вызывается каждые X секунд и дёргает асинхронную функцию:
А зачем используете именно этот таймер? Его особенность в том, что он функцию вызывает в потоке формы и из нее удобно обращаться к элементам формы.
А>Мне нужно чтобы при следующем тике таймера проверялось, закончился ли асинхронный запрос и если нет, то не вызывать эту функцию (DiscoverDevice). Можно конечно сделать глобальную переменную и проверять, но как сделать правильно?
Используйте System.Threading.Timer:
System.Threading.Timer timer1 = new System.Threading.Timer(_ => DiscoverDevice(), null, 0, period);
Здравствуйте, Spiceman, Вы писали:
А>>Мне нужно чтобы при следующем тике таймера проверялось, закончился ли асинхронный запрос и если нет, то не вызывать эту функцию (DiscoverDevice). Можно конечно сделать глобальную переменную и проверять, но как сделать правильно?
S>Используйте System.Threading.Timer: S>
Здравствуйте, Lloyd, Вы писали:
L>А это точно поможет?
Мда, что-то я ступил, таймер же также срабатывает — каждый раз просто создает новый поток из пула потоков. Тогда только с помощью флага разруливать.
А вообще мы еще не знаем какое поведение требуется ТС. Если таймер выполняется каждые 2 секунды, а метод выполнялся 3 секунды, то следующий вызов должен быть сразу после выполнения метода или через 4 секунды от начала работы таймера?
Здравствуйте, Spiceman, Вы писали:
S>Мда, что-то я ступил, таймер же также срабатывает — каждый раз просто создает новый поток из пула потоков. Тогда только с помощью флага разруливать.
S>А вообще мы еще не знаем какое поведение требуется ТС. Если таймер выполняется каждые 2 секунды, а метод выполнялся 3 секунды, то следующий вызов должен быть сразу после выполнения метода или через 4 секунды от начала работы таймера?
Через 4.
Re[2]: запуск по таймеру
От:
Аноним
Дата:
27.01.11 00:14
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Вообще говоря вызов BeginInvoke без соответствующего EndInvoke вызывает утечку ресурсов, так что по аккуратнее с этим.
А>Можно конечно сделать глобальную переменную и проверять, но как сделать правильно?
Правильно это когда используются механизмы синхронизации, очевидно же. Самый простой способ через интерлокеры (см. метод CompareExchange). Ещё можно использовать мониторы (см. метод TryEnter).
JID: x64j@jabber.ru
Re[3]: запуск по таймеру
От:
Аноним
Дата:
27.01.11 08:26
Оценка:
Здравствуйте, Аноним, Вы писали:
А>а можно пример как правильно?
На делегатах как-то так наверное (скорее всего можно и покороче оформить):
private DiscoveryMyDeviceDelegate DiscoveryDelegate
{
get
{
if (discoveryDelegate == null)
{
discoveryDelegate = new DiscoveryMyDeviceDelegate(DiscoverDevice);
}
return discoveryDelegate;
}
}
private DiscoveryMyDeviceDelegate discoveryDelegate;
private IAsyncResult discoveryAsyncResult;
private void timerFindDevice_Tick(object sender, EventArgs e)
{
if (discoveryAsyncResult == null)
{
discoveryAsyncResult = DiscoveryDelegate.BeginInvoke(null, null);
}
else if (discoveryAsyncResult.IsCompleted)
{
// try
DiscoveryDelegate.EndInvoke(discoveryAsyncResult); // Если в процессе работы были исключения, будут переброшены здесь
// catch (Exception ex) { ... }
discoveryAsyncResult = DiscoveryDelegate.BeginInvoke(null, null);
}
}
Но раз уж у вас WinForms, скорее всего проще будет воспользоваться компонентом BackgroundWorker — у него есть свойство IsBusy и событие Completed, которое генерируется в контексте GUI потока, что может быть весьма полезным.