#.net #process #synchronization #mutex
#.net #процесс #синхронизация #мьютекс
Вопрос:
Например, я создаю два процесса (ConsoleApplication2.exe ). Каждый из них записывает некоторый текст («dog» или «cat») в один и тот же текстовый файл: c:_threads_laboratorydata.txt . Я хочу получить результат:
собака,
кошка
,
кот
,
собака
,
собака
, кот
…
dog, кот
но я понимаю это:
собака
собаки
собаки
собаки
кота
собаки
кота
собаки
кота
собаки
кота
собаки
кота
собаки
кота
…
Почему я получаю неверный результат? Как я могу это исправить?
Мои процессы запускаются с помощью Launcher.exe:
// Program.cs
// It builds the Launcher.exe
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Launcher {
class Program {
static void Main(string[] args) {
Console.Title = "Launcher";
String fileFullName = @"c:_threads_laboratorydata.txt";
using (Mutex mutex = new Mutex(true, "my_mutex")) {
if (File.Exists(fileFullName))
File.Delete(fileFullName);
Process proc_1 = new Process();
String exeName = @".ConsoleApplication2.exe";
ProcessStartInfo info_1 = new ProcessStartInfo(exeName, "proc_#1 dog");
proc_1.StartInfo = info_1;
proc_1.Start();
Console.WriteLine("proc_#1 started by launcher...");
Process proc_2 = new Process();
ProcessStartInfo info_2 = new ProcessStartInfo(exeName, "proc_#2 cat");
proc_2.StartInfo = info_2;
proc_2.Start();
Console.WriteLine("proc #2 started by launcher...");
mutex.ReleaseMutex();
proc_1.WaitForExit();
proc_2.WaitForExit();
}
Console.WriteLine("Result in the "{0}" file.", fileFullName);
Console.WriteLine("Press any key for exit...");
Console.ReadKey();
}
}
}
ConsoleApplication2.exe код:
// Program_2.cs
// It builds the ConsoleApplication2.exe
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace ConsoleApplication2 {
class Program_2 {
static void Main(string[] args) {
if (2 != args.Length)
return;
Console.Title = args[0];
Mutex mutex = new Mutex(false, "my_mutex");
String dir = @"c:_threads_laboratory";
String file = "data.txt";
String fullName = Path.Combine(dir, file);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
String text = args[1];
Int32 counter = 100;
using (FileStream fs = File.Open(fullName, FileMode.Append,
FileAccess.Write, FileShare.ReadWrite)) {
using (StreamWriter sw = new StreamWriter(fs)) {
while (counter-- > 0) {
mutex.WaitOne();
fs.Position = fs.Length;
sw.WriteLine(text);
Console.Write("*");
sw.Flush();
fs.Flush(true);
mutex.ReleaseMutex();
Thread.Sleep(0);
}
sw.Close();
}
fs.Close();
}
}
}
}
Комментарии:
1. Почему вы вообще ожидаете какой-либо синхронизации? Результат должен быть абсолютно случайным.
2. потому что я использую именованный мьютекс для синхронизации процессов.
Ответ №1:
Я думаю, что вы путаете мьютексы и события. «Мьютекс» — это сокращение от «Взаимоисключающий» — ваш код только гарантирует, что два процесса не будут записывать данные в файл одновременно.
Что вам действительно нужно, так это два события; способ для одного процесса сигнализировать, что это сделано и теперь ожидает другого, и другое событие для обратного хода.
Комментарии:
1. «Пожалуйста, обратите внимание, что события в Windows не полностью защищены от условий гонки». Не могли бы вы пояснить?
2. Именованные мьютексы могут использоваться для синхронизации не только потоков, но и процессов (Справочник по C #4.0 Герберта Шилдта).
Ответ №2:
Вы получили синхронизацию. Несинхронизированный результат был бы чем-то вроде
docat
g
cat
cat
cadto
g
dog
catdog
cat
Комментарии:
1. Нет. Посмотрите внимательно на начало текстового файла.
2. @Bush: Вы полностью упустили разницу. В вашем примере выходные данные никогда не чередуются.