using System; using System.Text; using System.Threading.Tasks; namespace Multithreading { internal static class Program { private static readonly object _fileLock = new object(); public static void Main(string[] args) { Console.WriteLine("Program started"); // int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Task[] tasks = new Task[100]; // Random random = new Random(); // for (int i = 0; i < tasks.Length; i++) // { // tasks[i] = Task.Run(() => // { // for (int j = 0; j < numbers.Length; j++) // { // Console.WriteLine($"Before Thread Id: {Thread.CurrentThread.ManagedThreadId}, number({j}): {numbers[j]}"); // // Thread.Sleep(random.Next(0, 1000)); // // // not thread-safe // // int oldValue = numbers[j]; // // int newValue = oldValue * random.Next(10); // // numbers[j] = newValue; // // Thread.Sleep(random.Next(0, 1000)); // // Console.WriteLine($"After Thread Id: {Thread.CurrentThread.ManagedThreadId}, number({j}): {numbers[j]} / oldValue: {oldValue} / newValue: {newValue}"); // // // making this thread-safe // // option 1: lock // lock (numbers) // { // int oldValue = numbers[j]; // int newValue = oldValue * random.Next(10); // numbers[j] = newValue; // Thread.Sleep(random.Next(0, 1000)); // Console.WriteLine($"After Thread Id: {Thread.CurrentThread.ManagedThreadId}, number({j}): {numbers[j]} / oldValue: {oldValue} / newValue: {newValue}"); // } // // // option 2: use concurrent collections // // https://learn.microsoft.com/en-us/dotnet/standard/collections/thread-safe/ // // // option 3: use chunks to have no overlapping // // } // }); // } // Dictionary dictionary = new Dictionary(); // Task[] tasks = new Task[1000]; // Random random = new Random(); // for (int i = 0; i < tasks.Length; i++) // { // tasks[i] = Task.Run(() => // { // lock (dictionary) // one option, another option is to use ConcurrentDictionary // { // int key = random.Next(); // if (!dictionary.ContainsKey(key)) // { // // dictionary[key] = $"Thread Id: {Thread.CurrentThread.ManagedThreadId}, number({key}): {random.Next(10)}"; // dictionary.TryAdd(key, $"Thread Id: {Thread.CurrentThread.ManagedThreadId}, number({key}): {random.Next(10)}"); // } // } // }); // } Task[] tasks = new Task[100]; Random random = new Random(); File.Delete("output.txt"); for (int i = 0; i < tasks.Length; i++) { tasks[i] = Task.Run(() => { // not thread-safe // File.AppendAllText("output.txt", $"Thread Id: {Thread.CurrentThread.ManagedThreadId}, number: {random.Next(10)}\n"); // FileStream fs = File.OpenWrite("output.txt"); // FileStream fs = File.Open("output.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite); // string s = $"{Thread.CurrentThread.ManagedThreadId}, number: {random.Next(10)}\n"; // byte[] bytes = Encoding.UTF8.GetBytes(s); // fs.Write(bytes, 0, bytes.Length); // fs.Close(); // fs.Dispose(); // thread-safe lock (_fileLock) { FileStream fs = File.Open("output.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite); string s = $"{Thread.CurrentThread.ManagedThreadId}, number: {random.Next(10)}\n"; byte[] bytes = Encoding.UTF8.GetBytes(s); fs.Write(bytes, 0, bytes.Length); fs.Close(); fs.Dispose(); } }); } Task.WaitAll(tasks); Console.WriteLine("Program ended"); } } }