Есть сервис
class MainService : ServiceBase
{
event EventHandler MyEvent;
Thread m_Thread = null;
...
protected override void OnStart(string[] args)
{
//тут System.Threading.Thread.CurrentThread.ManagedThreadId = 1
MyEvent += delegate {
//Тут System.Threading.Thread.CurrentThread.ManagedThreadId = 5
};
m_Thread = new Thread(new ThreadStart(MonitorThread));
m_Thread.IsBackground = true;
m_Thread.Start();
}
protected override void OnStop()
{
m_Thread.Abort();
}
...
private void MonitorThread()
{
//Something
MyEvent?.Invoke(this, EventArg.Empty);
//Something
}
...
}
в MonitorThread иногда вызываются события MyEvent, естественно вызов происходит в потоке отличного от основного потока, как мне вызвать событие или какой-либо метод по событию в основном потоке???
PS: SynchronizationContext.Current в сервисе = null
PS2: Сборка в .Net Framework 2.0
Никак, основной поток в вин-службах полностью отведен под управление временем жизни и системные события (OnStart, OnStop и т.п.)
Если вам зачем-то нужен основной поток - надо просто выбрать один из ваших дополнительных потоков и "назначить" его основным.
Если вас не устраивает ваш MonitorThread в качестве такового - держите реализацию потока с очередью сообщений:
class QueueSynchronizationContext : SynchronizationContext, IDisposable
{
private readonly BlockingCollection<WorkItem> queue = new BlockingCollection<WorkItem>();
public override void Post(SendOrPostCallback d, object state)
{
try { queue.Add(new WorkItem(d, state)); }
catch (InvalidOperationException) { if (Debugger.IsAttached) Debugger.Break(); }
// Если уже был вызван CompleteAdding - мы уже не можем добавить элемент в очередь, но и позволять службе падать также не стоит
// (нет ничего глупее чем программа которая падает при закрытии). Поэтому лучшее что тут можно сделать - это забыть.
}
public override void Send(SendOrPostCallback d, object state)
{
try
{
using (var e = new ManualResetEvent(initialState: false))
{
queue.Add(new WorkItem(d, state, e));
e.WaitOne();
}
}
catch (InvalidOperationException) { if (Debugger.IsAttached) Debugger.Break(); }
// Если уже был вызван CompleteAdding - мы уже не можем добавить элемент в очередь, но и позволять службе падать также не стоит
// (нет ничего глупее чем программа которая падает при закрытии). Поэтому лучшее что тут можно сделать - это забыть.
}
public bool ProcessQueue(CancellationToken token)
{
try
{
foreach (var wi in queue.GetConsumingEnumerable(token))
wi.Execute();
return true;
}
catch (OperationCanceledException) { return false; }
}
public void Complete() => queue.CompleteAdding();
public void Dispose() => queue.Dispose();
private class WorkItem
{
private SendOrPostCallback d;
private object state;
private ManualResetEvent e;
public WorkItem(SendOrPostCallback d, object state, ManualResetEvent e = null)
{
this.d = d;
this.state = state;
this.e = e;
}
public void Execute()
{
try { d(state); }
finally { e?.Set(); }
}
}
}
class MyService : ServiceBase
{
private QueueSynchronizationContext ctx;
private Thread mainThread;
protected override void OnStart(string[] args)
{
this.ctx = new QueueSynchronizationContext();
this.mainThread = new Thread(MainThread);
this.mainThread.Start();
}
protected override void OnStop()
{
// Не забыть отменить фоновые задачи и дождаться их завершения
// ПЕРЕД вызовом ctx.Complete()!
ctx.Complete();
mainThread.Join();
ctx.Dispose();
}
private void MainThread()
{
SynchronizationContext.SetSynchronizationContext(ctx);
ctx.ProcessQueue(CancellationToken.None);
}
}
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости