другие потоки должны знать об изменениях сразу же
Если вы хотите получать уведомления с низкой задержкой, потоки должны тратить большую часть времени на сон.Например, выполнение Dispatcher.Run()
, которое будет спать в ожидании обработки сообщений / задач.
Если это ваш случай, вы можете использовать ObservableCollection
вместо List и написать обработчик CollectionChanged
, который пересылает уведомления для ваших 3 потоков,Или, если вы этого хотите, перенаправьте уведомления в 2 других потока, исключая текущий, если вы не хотите, чтобы поток, инициировавший изменение, обрабатывал измененное событие.
Я не уверен, что *Класс 1012 * доступен на платформе Windows IoT.Определенно не относится к ядру .NET.Даже если нет, доступны строительные блоки высокого уровня для их создания.Вот пример реализации, которая также реализует контекст синхронизации, очень простой, потому что использует универсальные классы высокого уровня ConcurrentQueue и BlockingCollection.
using kvp = KeyValuePair<SendOrPostCallback, object>;
enum eShutdownReason : byte
{
Completed,
Failed,
Unexpected,
}
class Dispatcher : IDisposable
{
const int maxQueueLength = 100;
readonly ConcurrentQueue<kvp> m_queue;
readonly BlockingCollection<kvp> m_block;
public Dispatcher()
{
m_queue = new ConcurrentQueue<kvp>();
m_block = new BlockingCollection<kvp>( m_queue, maxQueueLength );
createdThreadId = Thread.CurrentThread.ManagedThreadId;
prevContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext( new SyncContext( this ) );
}
readonly SynchronizationContext prevContext;
readonly int createdThreadId;
class SyncContext : SynchronizationContext
{
readonly Dispatcher dispatcher;
public SyncContext( Dispatcher dispatcher )
{
this.dispatcher = dispatcher;
}
// https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
public override void Post( SendOrPostCallback cb, object state )
{
dispatcher.Post( cb, state );
}
}
/// <summary>Run the dispatcher. Must be called on the same thread that constructed the object.</summary>
public eShutdownReason Run()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
while( true )
{
kvp h;
try
{
h = m_block.Take();
}
catch( Exception ex )
{
ex.logError( "Dispatcher crashed" );
return eShutdownReason.Unexpected;
}
if( null == h.Key )
return (eShutdownReason)h.Value;
try
{
h.Key( h.Value );
}
catch( Exception ex )
{
ex.logError( "Exception in Dispatcher.Run" );
}
}
}
/// <summary>Signal dispatcher to shut down. Can be called from any thread.</summary>
public void Stop( eShutdownReason why )
{
Logger.Info( "Shutting down, because {0}", why );
Post( null, why );
}
/// <summary>Post a callback to the queue. Can be called from any thread.</summary>
public void Post( SendOrPostCallback cb, object state = null )
{
if( !m_block.TryAdd( new kvp( cb, state ) ) )
throw new ApplicationException( "Unable to post a callback to the dispatcher: the dispatcher queue is full" );
}
void IDisposable.Dispose()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
SynchronizationContext.SetSynchronizationContext( prevContext );
}
}
Независимо от того, будете ли вы использовать встроенный Dispatcher или мой пользовательский, всепотоки должны вызывать метод Run, а затем использовать асинхронные опубликованные задачи или асинхронные методы для запуска кода в диспетчере.