Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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_Thread Safety_Thread Synchronization - Fatal编程技术网

C# 无锁线程安全状态同步?

C# 无锁线程安全状态同步?,c#,multithreading,thread-safety,thread-synchronization,C#,Multithreading,Thread Safety,Thread Synchronization,首先,我知道这样的问题: 。。。但我仍然不确定是否可以在我的案例中避免使用lock(){} 在我的例子中,我有一个表示某种状态的类,只有一个线程会不时修改该状态。但是有许多线程读取状态 是否需要在state对象上使用Interlocked.Exchange()? 我一定要使用lock(){} 下面是我的示例代码,简化到最低限度: using System; using System.Collections.Generic; using System.Threading; using Syste

首先,我知道这样的问题:

。。。但我仍然不确定是否可以在我的案例中避免使用lock(){}

在我的例子中,我有一个表示某种状态的类,只有一个线程会不时修改该状态。但是有许多线程读取状态

是否需要在state对象上使用Interlocked.Exchange()? 我一定要使用lock(){}

下面是我的示例代码,简化到最低限度:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace MultiThreadingExample
{
class State
{
    public int X { get; set; }
    public string Str { get; set; }
    public DateTime Current { get; set; }
}

class Example
{
    State state;
    CancellationTokenSource cts = new CancellationTokenSource();

    Task updater;
    List<Task> readers = new List<Task>();

    public void Run()
    {
        updater = Task.Factory.StartNew(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                // wait until we have a new state from some source
                Thread.Sleep(1000);

                var newState = new State() { Current = DateTime.Now, X = DateTime.Now.Millisecond, Str = DateTime.Now.ToString() };

                // critical part
                state = newState;
            }
        }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

        for (int i = 0; i < 10; i++)
        {
            readers.Add(Task.Factory.StartNew(() =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    // critical part
                    var readState = state;

                    // use it
                    if (readState != null)
                    {
                        Console.WriteLine(readState.Current);
                        Console.WriteLine(readState.Str);
                        Console.WriteLine(readState.X);
                    }
                }
            }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default));
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        new Example().Run();
        Console.ReadKey();
    }
}
}
使用系统;
使用System.Collections.Generic;
使用系统线程;
使用System.Threading.Tasks;
名称空间多线程示例
{
阶级国家
{
公共整数X{get;set;}
公共字符串Str{get;set;}
公共日期时间当前{get;set;}
}
课例
{
国家;
CancellationTokenSource cts=新的CancellationTokenSource();
任务更新程序;
列表阅读器=新列表();
公开募捐
{
updater=Task.Factory.StartNew(()=>
{
而(!cts.Token.IsCancellationRequested)
{
//等到我们从某个来源得到一个新的状态
睡眠(1000);
var newState=newState(){Current=DateTime.Now,X=DateTime.Now.毫秒,Str=DateTime.Now.ToString()};
//关键部分
状态=新闻状态;
}
},cts.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default);
对于(int i=0;i<10;i++)
{
readers.Add(Task.Factory.StartNew(()=>
{
而(!cts.Token.IsCancellationRequested)
{
//关键部分
var readState=状态;
//使用它
if(readState!=null)
{
Console.WriteLine(readState.Current);
Console.WriteLine(readState.Str);
Console.WriteLine(readState.X);
}
}
},cts.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default));
}
}
}
班级计划
{
静态void Main(字符串[]参数)
{
新示例().Run();
Console.ReadKey();
}
}
}

如果您只有一个正在更新的线程和一个正在读取的线程,我相信您不会遇到任何运行时错误。然而,您的示例显示了10个读卡器线程。话虽如此,我认为您不应该假设您不需要任何东西来确保应用程序线程安全。您应该至少引入锁定,以确保线程之间能够很好地配合。因为当您读取读取器线程中的值时,状态对象是一个复杂的对象,所以您可能无法获得预期的所有内容。在读取操作期间,如果不锁定,可能会更改一个或两个属性,但不会更改第三个属性。下面是我正在谈论的修改示例

class State
{
    public int X { get; set; }
    public string Str { get; set; }
    public DateTime Current { get; set; }
}

class Example
{
    State state;
    CancellationTokenSource cts = new CancellationTokenSource();
    Object syncObj = new Object();
    Task updater;
    List<Task> readers = new List<Task>();

    public void Run()
    {
        updater = Task.Factory.StartNew(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                // wait until we have a new state from some source
                Thread.Sleep(1000);

                var newState = new State() { Current = DateTime.Now, X = DateTime.Now.Millisecond, Str = DateTime.Now.ToString() };

                // critical part
                lock(syncObj) {
                    state = newState;
                }
            }
        }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

        for (int i = 0; i < 10; i++)
        {
            readers.Add(Task.Factory.StartNew(() =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    State readState = null;

                    // critical part
                    lock(syncObj) {
                        readState = state.Clone();
                    }

                    // use it
                    if (readState != null)
                    {
                        Console.WriteLine(readState.Current);
                        Console.WriteLine(readState.Str);
                        Console.WriteLine(readState.X);
                    }
                }
            }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default));
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        new Example().Run();
        Console.ReadKey();
    }
}
类状态
{
公共整数X{get;set;}
公共字符串Str{get;set;}
公共日期时间当前{get;set;}
}
课例
{
国家;
CancellationTokenSource cts=新的CancellationTokenSource();
Object syncObj=新对象();
任务更新程序;
列表阅读器=新列表();
公开募捐
{
updater=Task.Factory.StartNew(()=>
{
而(!cts.Token.IsCancellationRequested)
{
//等到我们从某个来源得到一个新的状态
睡眠(1000);
var newState=newState(){Current=DateTime.Now,X=DateTime.Now.毫秒,Str=DateTime.Now.ToString()};
//关键部分
锁(同步对象){
状态=新闻状态;
}
}
},cts.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default);
对于(int i=0;i<10;i++)
{
readers.Add(Task.Factory.StartNew(()=>
{
而(!cts.Token.IsCancellationRequested)
{
State readState=null;
//关键部分
锁(同步对象){
readState=state.Clone();
}
//使用它
if(readState!=null)
{
Console.WriteLine(readState.Current);
Console.WriteLine(readState.Str);
Console.WriteLine(readState.X);
}
}
},cts.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default));
}
}
}
班级计划
{
静态void Main(字符串[]参数)
{
新示例().Run();
Console.ReadKey();
}
}

这是一个很小的更改,但它将确保您在状态对象方面是线程安全的。

如果您只有一个正在更新的线程和一个正在读取的线程,我相信您不会遇到任何运行时错误。然而,您的示例显示了10个读卡器线程。话虽如此,我认为您不应该假设您不需要任何东西来确保应用程序线程安全。您应该至少引入锁定,以确保线程之间能够很好地配合。因为当您读取读取器线程中的值时,状态对象是一个复杂的对象,所以您可能无法获得预期的所有内容。在读取操作期间,如果不锁定,可能会更改一个或两个属性,但不会更改第三个属性。下面是我正在谈论的修改示例

class State
{
    public int X { get; set; }
    public string Str { get; set; }
    public DateTime Current { get; set; }
}

class Example
{
    State state;
    CancellationTokenSource cts = new CancellationTokenSource();
    Object syncObj = new Object();
    Task updater;
    List<Task> readers = new List<Task>();

    public void Run()
    {
        updater = Task.Factory.StartNew(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                // wait until we have a new state from some source
                Thread.Sleep(1000);

                var newState = new State() { Current = DateTime.Now, X = DateTime.Now.Millisecond, Str = DateTime.Now.ToString() };

                // critical part
                lock(syncObj) {
                    state = newState;
                }
            }
        }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

        for (int i = 0; i < 10; i++)
        {
            readers.Add(Task.Factory.StartNew(() =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    State readState = null;

                    // critical part
                    lock(syncObj) {
                        readState = state.Clone();
                    }

                    // use it
                    if (readState != null)
                    {
                        Console.WriteLine(readState.Current);
                        Console.WriteLine(readState.Str);
                        Console.WriteLine(readState.X);
                    }
                }
            }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default));
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        new Example().Run();
        Console.ReadKey();
    }
}
类状态
{
公共整数X{get;set;}
公共字符串Str{get;set;}
公共日期时间当前{get;set;}
}
课例
{
国家;
CancellationTokenSource cts=新的CancellationTokenSource();
Object syncObj=新对象();
任务更新
// read and swap with null atomically
var readState = Interlocked.Exchange(ref state, null);
BlockingCollection<State> queue = new BlockingCollection<State>();

updater = Task.Factory.StartNew(() =>
{
    while (!cts.Token.IsCancellationRequested)
    {
        Thread.Sleep(1000);

        var newState = GetNewState();

        queue.Add(newState);
    }
}, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

for (int i = 0; i < 10; i++)
{
    var readerId = i.ToString();

    readers.Add(Task.Factory.StartNew(() =>
    {
        while (!cts.Token.IsCancellationRequested)
        {
            // get it
            var readState = queue.Take(cts.Token);

            // use it
            if (readState != null)
            {
                Console.WriteLine("Hello from reader #" + readerId);
                Console.WriteLine(readState.X);
            }
        }
    }, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default));
}