Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在主线程中读取/写入全局变量_C#_Multithreading_Iot_Windows 10 Iot Core - Fatal编程技术网

C# 如何在主线程中读取/写入全局变量

C# 如何在主线程中读取/写入全局变量,c#,multithreading,iot,windows-10-iot-core,C#,Multithreading,Iot,Windows 10 Iot Core,我创建了一个C#Windows IoT后台应用程序。该应用程序的线程池中有多个线程无限期运行 这些线程需要能够读/写主线程中的全局变量,但我不确定如何实现这一点。下面是我正在尝试做的一个例子: // main task public sealed class StartupTask : IBackgroundTask { private static BackgroundTaskDeferral _Deferral = null; private static MyThread

我创建了一个C#Windows IoT后台应用程序。该应用程序的线程池中有多个线程无限期运行

这些线程需要能够读/写主线程中的全局变量,但我不确定如何实现这一点。下面是我正在尝试做的一个例子:

// main task
public sealed class StartupTask : IBackgroundTask
{
    private static BackgroundTaskDeferral _Deferral = null;

    private static MyThreadClass1 thread1 = null;
    private static MyThreadClass2 thread2 = null;
    private static MyThreadClass3 thread3 = null;

    List<Object> MyDevices = null;

    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        _Deferral = taskInstance.GetDeferral();

        MyDevices = GetDeviceList();

        thread1 = new MyThreadClass1();
        await ThreadPool.RunAsync(workItem =>
        {
            thread1.Start();
        });

        thread2 = new MyThreadClass2();
        await ThreadPool.RunAsync(workItem =>
        {
            thread2.Start();
        });

        thread3 = new MyThreadClass3();
        await ThreadPool.RunAsync(workItem =>
        {
            thread3.Start();
        });
    }
}

internal class MyThreadClass1
{
    public async void Start()
    { }
}

internal class MyThreadClass2
{
    public async void Start()
    { }
}

internal class MyThreadClass3
{
    public async void Start()
    { }
}
//主要任务
公共密封类StartupTask:IBackgroundTask
{
私有静态背景任务延迟_deleral=null;
私有静态MyThreadClass1 thread1=null;
私有静态MyThreadClass2 thread2=null;
私有静态MyThreadClass3 thread3=null;
List MyDevices=null;
公共异步无效运行(IBackgroundTaskInstance taskInstance)
{
_延迟=taskInstance.getDeleral();
MyDevices=GetDeviceList();
thread1=新的MyThreadClass1();
等待ThreadPool.RunAsync(workItem=>
{
thread1.Start();
});
thread2=新的MyThreadClass2();
等待ThreadPool.RunAsync(workItem=>
{
thread2.Start();
});
thread3=新的MyThreadClass3();
等待ThreadPool.RunAsync(workItem=>
{
thread3.Start();
});
}
}
内部类MyThreadClass1
{
公共异步void Start()
{ }
}
内部类MyThreadClass2
{
公共异步void Start()
{ }
}
内部类MyThreadClass3
{
公共异步void Start()
{ }
}
在正在运行的三个线程中的任何一个线程中,我都需要能够读写
列出我的设备

这些线程都有不同的功能,但它们都与“MyDevices”交互,因此如果一个线程对该列表进行了更改,其他线程需要立即了解更改

做这件事最好的方法是什么


谢谢

>你想考虑的一件事是A.此类实现了
INotifyPropertyChanged
接口,该接口通知任何侦听器底层集合的更改

接下来,您需要在
线程
类中为
属性更改
实现一个事件处理程序,如下所示(我建议创建一个接口或基类来处理此问题,因为您似乎对每个
线程
使用不同的类):

公共密封类MyThreadBase
{
专用可观测采集设备;
公共MyThreadBase(ObservableCollection deviceList)
{
我的设备=设备主义者;
MyDevices.PropertyChanged+=MyDevices\u PropertyChanged;//注册侦听器
}
私有void MyDevices\u PropertyChanged(对象发送方,PropertyChangedEventArgs e)
{
锁(我的设备)
{
//对数据做点什么。。。
}
}
}
使用
lock
语句,以便在另一个线程正在读取或写入
MyDevices
时阻止该线程。这在同步中通常很重要,称为。我建议大家仔细研究一下这个问题以及可能的解决办法

但是,如果您打算让每个线程在设备上迭代并对每个设备执行某些操作,那么您将遇到问题,因为迭代更改的集合不是一个好主意(并且在使用
foreach
循环时,实际上会抛出一个异常),因此也请记住这一点

其他线程需要立即了解更改

如果您想要低延迟通知,线程必须将大部分时间花在睡眠上。例如,执行
Dispatcher.Run()
,它将休眠等待消息/任务处理

如果是这种情况,您可以使用
ObservableCollection
而不是List,并编写
CollectionChanged
处理程序来转发3个线程的通知。或者,如果您不希望启动更改以处理更改事件的线程,则可以将通知转发给其他两个线程(当前线程除外)

我不确定
Dispatcher
类是否在Windows IoT平台上可用。绝对不是.NETCore的情况。即使没有,也可以使用高级构建块来创建一个。这里的示例实现也实现了同步上下文,非常简单,因为它依赖于高级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 );
    }
}
使用kvp=KeyValuePair;
枚举eShutdownReason:字节
{
完整的,
失败,
想不到的
}
类调度程序:IDisposable
{
const int maxQueueLength=100;
只读并发队列m_队列;
只读块集合m_块;
公共调度程序()
{
m_queue=新的ConcurrentQueue();
m_block=新BlockingCollection(m_队列,maxQueueLength);
createdThreadId=Thread.CurrentThread.ManagedThreadId;
prevContext=SynchronizationContext.Current;
SetSynchronizationContext(新的SyncContext(this));
}
只读同步上下文prevContext;
只读int createdThreadId;
类SyncContext:SynchronizationContext
{
只读调度器;
公共同步上下文(调度程序)
{
this.dispatcher=dispatcher;
}
// https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
公共覆盖无效Post(SendOrPostCallback cb,对象状态)
{
调度员岗(cb,州);
}
}
///必须在构造该对象的同一线程上调用。
公共eShutdownReason运行()
{
Assert(Thread.CurrentThread.ManagedThreadId==createdThreadId);
while(true)
{
kvph;
尝试
{
h=m_块。取();
}
捕获(例外情况除外)
{
例如logError(“
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 );
    }
}
object _mutex = new object();
List<Object> MyDevices = null;

...

var device = ...;
lock (_mutex)
{
  MyDevices.Add(device);
}