Reputation:
I have code like this, some threads will generate string (here 100) and store to array, other single thread will read data using indexer [] and save to file. I used Interlocked class for string swapping in ThreadSafeString class but I don't know if its enough to avoid deadlocks and non thread safe problems. Other idea I have is to use ConcurrentDirectory<int, string>
to be sure its safe.
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();
}
}
}
Upvotes: 2
Views: 196
Reputation: 2722
EDIT:
To reflect your comment I changed to the use of ConcurrentDictionary
.
The dictionary will take care for the threadsafe reading and writing of the strings.
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();
}
}
}
Upvotes: 0
Reputation: 5353
I don't see a point in ThreadSafeString here. Use Interlocked.CompareExchange
if you need to compare, store and return old data as a single operation.
Interlocked.CompareExchange(ref _string, null, null);
means
if (_string == null)
{
_string = null;
return null;
} else return _string;
but as a single operation. As you can see it can be easily replaced with
return __string;
same with Interlocked.Exchange
- you don't need to do it for strings:
Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types.
You need to do it only for types other than that and if you need to get old value as an atomic operation.
Simply using string[]
here will have same thread-safety. You can safely store and read data from array as long as you don't change array size and operate on reference types or single word sized value types. You only need to worry about thread-safety if you want to read, change and store data back, but this is another problem that is not even solved by collections like ConcurrentDirectory
Upvotes: 1