У меня есть довольно сложная проблема программирования на руках, так что несите меня в течение нескольких минут.Синхронизация между несколькими экземплярами одной и той же программы
Я решил создать медиа-плеер в WPF (C#), и я столкнулся с немного рассолом.
Я хочу, чтобы мое приложение было единым экземпляром, так что, когда пользователь дважды щелкает файлы сервера, программа запускается только один раз и ставит в очередь все файлы для воспроизведения.
Я пробовал несколько способов сделать это, включая реализацию одного экземпляра Microsoft, и ничего не работало, пока я не решил создать свой собственный, как в i хоть что-то и реализовал его (это, вероятно, было в Интернете где-то также, но это не отображалось)
В принципе, я использую именованный мьютекс, чтобы предотвратить открытие нескольких экземпляров, а также заставить другие экземпляры записывать свои аргументы в файл, а после этого , экземпляр, создавший мьютекс, будет читать файл. Излишне говорить, что это очень, очень неэффективно, поскольку производительность идет, но в любом случае, вот моя реализация функции Main(). Обратите внимание, что этот Main() также написан с нуля, так как мне не понравился тот, который автоматически генерируется VS2010.
static void Main(string[] args)
{
string[] arguments = new string[0];
handler g = new handler();
bool createdNew = false;
Mutex lolpaca = new Mutex(true, "lolpacamaximumtrolololololol", out createdNew);
if (createdNew)
{
if (args != null)
{
var MainWindow = new MainWindow();
var app = new Application();
app.Run(MainWindow);
lolpaca.ReleaseMutex();
lolpaca.Dispose();
}
else
{
Array.Resize(ref arguments, 1);
arguments[0] = args[0];
string line;
//nu mai arunca exceptii nenorocitule
while ((line = g.ReadArgs()) != null)
{
int old_size = arguments.Length;
Array.Resize(ref arguments, arguments.Length + 1);
arguments[old_size] = line;
}
var MainWindow = new MainWindow(arguments, arguments.Length);
var app = new Application();
app.Run(MainWindow);
lolpaca.ReleaseMutex();
lolpaca.Dispose();
}
if (File.Exists(path))
{
File.Delete(path);
}
}
else
{
Thread writer = new Thread(new ParameterizedThreadStart(g.WriteArg));
writer.Start(args);
writer.Join();
try
{
g.WriteArg(args);
}
catch (IOException e)
{
MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source);
exp.Show();
}
}
}
Я также использую этот класс, чтобы попытаться синхронизировать между нитями
public class handler
{
static string path = @"D:\playlist.txt";
static FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
string line;
string arg;
bool readerFlag = false;
public string ReadArgs()
{
try
{
lock (fs) // Enter synchronization block
{
if (!readerFlag)
{ // Wait until writer finishes
try
{
// Waits for the Monitor.Pulse in WriteArg
Monitor.Wait(fs);
}
catch (SynchronizationLockException)
{
}
catch (ThreadInterruptedException)
{
}
}
TextReader tr = new StreamReader(fs);
while ((line = tr.ReadLine()) != null)
{
arg = line;
}
tr.Close();
tr.Dispose();
}
/* fs.Close();
fs.Dispose();*/
readerFlag = false;
Monitor.Pulse(fs);
return arg;
}
catch (IOException e)
{
MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source);
exp.Show();
return null;
}
}
public void WriteArg(object args)
{
lock (fs)
{
try
{
if (readerFlag)
{
try
{
Monitor.Wait(fs); // Wait for the Monitor.Pulse in ReadArgs
}
catch (SynchronizationLockException)
{
}
catch (ThreadInterruptedException)
{
}
}
arg = Convert.ToString(args);
// FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read);
TextWriter tw = new StreamWriter(fs);
tw.WriteLine(args);
tw.Close();
tw.Dispose();
}
catch (IOException e)
{
MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source);
exp.Show();
}
}
/* fs.Close();
fs.Dispose();*/
readerFlag = true;
Monitor.Pulse(fs);
}
}
Сейчас, в основном, для каждого двойного щелкнутой файла, один экземпляр Main() функция создается Windows. Первый экземпляр имеет контроль над мьютексом и переходит к тому, что он хочет делать. Другие экземпляры должны записать свой аргумент в файл.
Теперь проблема: По-видимому, нити (все они) не синхронизируются должным образом, а иногда я получаю исключения IO. У меня нет подсказки, где именно эти исключения выбрасываются, потому что блоки try-catch, похоже, ничего не делают. На самом деле, я считаю, что это немного глубже, чем попытаться поймать.
Итак, как мне синхронизировать все потоки, которые появляются, когда пользователь дважды щелкает много файлов? Эта реализация работает нормально с 3 файлами с двойным щелчком, а иногда (обратите внимание, иногда это работает, иногда это не так) с более чем 3 файлами (проверено до 9). Ничего, что я нашел до сих пор в Интернете, вызывает несколько экземпляров одного и того же приложения, работающих независимо.
Было бы здорово, если бы вы дать мне пример :)
Спасибо.
Не используйте файлы для обмена между процессами. Отправьте файл спецификаций на уже запущенный экземпляр в сообщении WM_COPYDATA, используйте каналы, используйте TCP, почти все, кроме файлов на диске. –
И как именно я взаимодействую с win-сообщениями в WPF? пока я знаю, WPF делает все возможное, чтобы вы этого не делали. –
Не обращайте на это внимания: P –