C# 多线程阵列线程安全?

C# 多线程阵列线程安全?,c#,multithreading,C#,Multithreading,我有这样的代码,一些线程将生成字符串(这里是100)并存储到数组中,其他单个线程将使用indexer[]读取数据并保存到文件中。我在ThreadSafeString类中使用Interlocked类进行字符串交换,但我不知道这是否足以避免死锁和非线程安全问题。我的另一个想法是使用ConcurrentDirectory来确保它的安全 using System; using System.IO; using System.Threading; namespace Test { class T

我有这样的代码,一些线程将生成字符串(这里是100)并存储到数组中,其他单个线程将使用indexer[]读取数据并保存到文件中。我在ThreadSafeString类中使用Interlocked类进行字符串交换,但我不知道这是否足以避免死锁和非线程安全问题。我的另一个想法是使用
ConcurrentDirectory
来确保它的安全

using System;
using System.IO;
using System.Threading;

namespace Test
{
    class ThreadSafeString
    {
        private string _string;

        public string Value
        {
            get => Interlocked.CompareExchange(ref _string, null, null);
            set => Interlocked.Exchange(ref _string, value);
        }
    }

    class Program
    {
        private static readonly ThreadSafeString[] array = new ThreadSafeString[100];

        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++) array[i] = new ThreadSafeString();

            for (int i = 0; i < 100; i++)
            {
                var thread = new Thread(() =>
                {
                    while (true)
                    {
                        string data = "";
                        //generate data

                        array[i].Value = data;
                        Thread.Sleep(100);
                    }
                });
                thread.Name = i.ToString();
                thread.Start();
            }

            var ht = new Thread(() =>
            {
                while (true)
                {
                    for (int i = 0; i < 100; i++)
                    {
                        string temp = array[i].Value;
                        File.WriteAllText(path, temp);
                    }

                    Thread.Sleep(2000);
                }
            });
            ht.Start();

            Console.ReadKey();
        }
    }
}
使用系统;
使用System.IO;
使用系统线程;
名称空间测试
{
类ThreadSafeString
{
私有字符串_字符串;
公共字符串值
{
get=>Interlocked.CompareExchange(ref\u字符串,null,null);
set=>Interlocked.Exchange(参考字符串,值);
}
}
班级计划
{
私有静态只读ThreadSafeString[]数组=新ThreadSafeString[100];
静态void Main(字符串[]参数)
{
对于(int i=0;i<100;i++)数组[i]=new ThreadSafeString();
对于(int i=0;i<100;i++)
{
变量线程=新线程(()=>
{
while(true)
{
字符串数据=”;
//生成数据
数组[i]。值=数据;
睡眠(100);
}
});
thread.Name=i.ToString();
thread.Start();
}
var ht=新线程(()=>
{
while(true)
{
对于(int i=0;i<100;i++)
{
字符串温度=数组[i]。值;
File.WriteAllText(路径,临时);
}
《睡眠》(2000年);
}
});
ht.Start();
Console.ReadKey();
}
}
}
编辑: 为了反映您的评论,我改为使用
ConcurrentDictionary

字典将负责字符串的线程安全读写

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace TestConsole
{
    internal class Program
    {
        private static void Main()
        {
            ConcurrentDictionary<int, string> threadResults = new ConcurrentDictionary<int, string>();

            for (int i = 0; i < 100; i++)
            {
                new Thread(() =>
                {
                    while (true)
                    {
                        string data = i.ToString();
                        threadResults.AddOrUpdate(i, data, (id, x) => data);
                        Thread.Sleep(100);
                    }
                }).Start();
            }

            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    foreach (var threadResult in threadResults)
                    {
                        Console.WriteLine($"{threadResult.Key} {threadResult.Value}");
                    }

                    Console.WriteLine();
                    Thread.Sleep(2000);
                }
            });

            Console.WriteLine("press return to exit...");
            Console.ReadLine();
        }
    }
}
使用系统;
使用System.Collections.Concurrent;
使用系统线程;
使用System.Threading.Tasks;
命名空间测试控制台
{
内部课程计划
{
私有静态void Main()
{
ConcurrentDictionary threadResults=新建ConcurrentDictionary();
对于(int i=0;i<100;i++)
{
新线程(()=>
{
while(true)
{
字符串数据=i.ToString();
AddOrUpdate(i,数据,(id,x)=>data);
睡眠(100);
}
}).Start();
}
Task.Factory.StartNew(()=>
{
while(true)
{
foreach(threadResults中的var threadResult)
{
WriteLine($“{threadResult.Key}{threadResult.Value}”);
}
Console.WriteLine();
《睡眠》(2000年);
}
});
Console.WriteLine(“按回车键退出…”);
Console.ReadLine();
}
}
}

我看不出ThreadSafeString在这里有什么意义。如果需要将旧数据作为单个操作进行比较、存储和返回,请使用
Interlocked.compareeexchange

Interlocked.CompareExchange(ref _string, null, null);
意味着

但是作为一个单一的操作。正如你所看到的,它很容易被替换为

return __string;
与联锁的
相同。Exchange
-您不需要对字符串执行此操作:

以下数据类型的读写是原子的:bool、char、, byte、sbyte、short、ushort、uint、int、float和引用类型

您只需要对除此之外的类型执行此操作,并且如果需要将旧值作为原子操作获取,则需要执行此操作。
在这里简单地使用
string[]
将具有相同的线程安全性。只要不更改数组大小并对引用类型或单字大小的值类型进行操作,就可以安全地存储和读取数组中的数据。如果您想读取、更改和存储数据,您只需要担心线程安全,但这是另一个像
ConcurrentDirectory

这样的集合甚至无法解决的问题。您为什么要这样做?这是学校的练习吗?否则,请使用内置在.NetSounds中的并发集合,就像用于。。。别的。并行LINQ(
Enumerable.AsParallel()
),即,
Parallel。对于[每个]
任务
s,请选择。从并行计算中手动收集结果在理想情况下是你不想为自己操心的事情。我想使用并发集合,但只有字典是基于键的,理想情况下我需要列表或数组之类的东西。这不是学校用的,我有一个应用程序,多线程正在做这项工作,需要集合来安装快照(字符串)要知道线程上一个任务做了什么。单线程正在将此保存到文件中,因此在崩溃后,我可以从它停止的位置开始。@3v0感谢您的响应,但我只需要线程中最新的数据,例如一个线程将在200ms内处理数据,另一个线程将在1000ms内处理数据,保存到队列中的2s。线程1和线程2将分别有10个字符串(只需要thread1中的1和thread2中的1)。我不想减少光盘性能的保存延迟。@3v0我更新了我的答案以反映您的评论。希望我答对了。谢谢,这是wokring!很好的观点,但其他问题是string[]适用于多线程保存和读取。我不会在生成字符串后修改字符串,我只需要将它们传输到一个线程进行保存。确实如此。这就是所有线程安全集合在下面的工作方式。它们唯一要做的是对数组进行版本设置并管理对它们的访问
return __string;