Задача на многопоточность. Полусинхронный вызов делегата
Задача В .net есть возможность звать делегаты как синхронно:
EventHandler h = new EventHandler(this.myEventHandler);
h.Invoke(null, EventArgs.Empty);
так и асинхронно:
var res = h.BeginInvoke(null, EventArgs.Empty, null, null);
Нужно реализовать возможность полусинхронного вызова делегата (написать реализацию класса AsyncCaller), который бы работал таким образом:
EventHandler h = new EventHandler(this.myEventHandler);
ac = new AsyncCaller(h);
bool completedOK = ac.Invoke(5000, null, EventArgs.Empty);
Полусинхронного в данном случае означает, что делегат будет вызван, и вызывающий поток будет ждать, пока вызов не выполнится. Но если выполнение делегата займет больше 5000 миллисекунд, то ac.Invoke выйдет и вернет в completedOK значение false.
Подскажите как лучше делать, или что посмотреть.
Ответы (1 шт):
Вы просите странного, Delegate.BeginInvoke не поддерживается со времен .NET Core 2.0, то есть достаточно давно. EAP устарел, позвольте ему покоиться с миром. Пора бы уже изучать TAP.
Но если очень хочется, то почему бы и нет.
class Program
{
private void MyEventHandler(object sender, EventArgs e)
{
Console.WriteLine("Enter Handler");
Thread.Sleep(1000);
Console.WriteLine("Exit Handler");
}
private void Run()
{
EventHandler h = new EventHandler(MyEventHandler);
AsyncCaller ac = new AsyncCaller(h);
if (ac.Invoke(5000, this, EventArgs.Empty))
Console.WriteLine("Completed successfully");
else
Console.WriteLine("Timeout occured");
}
static void Main(string[] args)
{
new Program().Run();
Console.WriteLine("Done.");
Console.ReadKey();
}
}
public class AsyncCaller
{
private readonly EventHandler handler;
private Thread thread;
public AsyncCaller(EventHandler handler)
{
this.handler = handler;
}
private void Aborter(IAsyncResult ar)
{
thread?.Abort();
}
private void Wait(object timeout)
{
Thread.Sleep((int)timeout);
}
public bool Invoke(int timeout, object sender, EventArgs e)
{
thread = new Thread(Wait);
IAsyncResult asyncResult = handler?.BeginInvoke(sender, e, Aborter, this);
thread.Start(timeout);
thread.Join();
thread = null;
return asyncResult.IsCompleted;
}
}
Запускаем делегат, который работает секунду, получаем:
Enter Handler
Exit Handler
Completed successfully
Done.
Меняем 1000 на 6000, получаем
Enter Handler
Timeout occured
Done.
Exit Handler
А теперь то же самое, только с использованием TAP
private static async Task HandleAsync()
{
Console.WriteLine("Enter Handler");
await Task.Delay(1000);
Console.WriteLine("Exit Handler");
}
static async Task Main(string[] args)
{
Task t = HandleAsync();
if (await Task.WhenAny(t, Task.Delay(5000)) == t)
Console.WriteLine("Completed successfully");
else
Console.WriteLine("Timeout occured");
Console.WriteLine("Done.");
Console.ReadKey();
}
Вывод при аналогичных ожиданиях такой же.
Обе реализации не идеальны и я бы допилил в сторону усложнения и более оптимальной работы с потоками, но оставил чем проще - тем лучше, главное чтобы работало.