Использование EventWaitHandle для обеспечения единого экземпляра для нескольких пользователей

Соавторы создали прототип, используя Processing, который подключается к считывателю Sparkfun RFID, я думаю, с использованием последовательного соединения через USB. Мы развернули прототип в нескольких домах испытателей, и один распространенный сценарий использования, который я по глупости упустил из виду, заключался в переключении пользователей. Поэтому я пишу оболочку, которая гарантирует, что только один экземпляр приложения-прототипа работает для всех пользователей на машине.

Я тестирую свой первый опыт в качестве простого консольного приложения. Вот код:

    static void Main(string[] args)
    {
        // http://stackoverflow.com/a/2590446/575530
        var users = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
        var rule = new EventWaitHandleAccessRule(users, EventWaitHandleRights.FullControl, AccessControlType.Allow);
        var security = new EventWaitHandleSecurity();
        security.AddAccessRule(rule);
        bool createdStartup;
        using (var whStartup = new EventWaitHandle(false, EventResetMode.AutoReset, "Global/AaltoTokensAppStartupEvent", out createdStartup, security))
        {
            bool createdShutdown;
            using (var whShutdown = new EventWaitHandle(false, EventResetMode.AutoReset, "Global/AaltoTokensAppShutdownEvent", out createdShutdown, security))
            {
                Console.WriteLine("Let other instances shutdown");
                whStartup.Set();
                Console.WriteLine("If other instances exist wait for them to shutdown");
                if (!createdShutdown)
                {
                    whShutdown.WaitOne();
                }
                whShutdown.Reset();
                Console.WriteLine("Start tray app");
                var tokenProc = Process.Start(@"C:\Temp\FAMILY3_WIN\TokensApp.exe");
                Console.WriteLine(tokenProc.ProcessName);
                Console.WriteLine("Wait to see if another instance to tries to start");
                whStartup.Reset();
                whStartup.WaitOne();
                Console.WriteLine("Shutdown if another instance starts");
                //if (tokenProc != null) tokenProc.Kill();
                foreach (var process in Process.GetProcesses())
                {
                    if (process.ProcessName.StartsWith("javaw"))
                    {
                        process.Kill();
                    }
                }
                whShutdown.Set();
            }
        }
        Console.WriteLine("Done...");
        Console.ReadLine();
    }

(Примечание. Я знаю, что с этим кодом есть проблемы, связанные с (1) уничтожением процессов Java, которые не являются запущенным прототипом, и (2) отсутствием кода для реагирования на множество экземпляров, запускаемых одновременно, только два за раз. Но это не то, что я вопрос примерно)

Тестирование этого под одной учетной записью пользователя работает нормально. Я могу запустить свое приложение, оно, в свою очередь, запускает прототип, и если я запускаю второй экземпляр своего приложения, первый убивает начальный экземпляр прототипа, прежде чем второй запускает другой экземпляр прототипа заново.

Но если я попытаюсь сделать это из двух разных учетных записей пользователей, это не удастся (молча). Если я

  1. Запустите экземпляр моего приложения, он запускает прототип
  2. Поменять пользователя
  3. Запустите экземпляр моего приложения, затем он запустит прототип без моего приложения с шага 1, сначала отключив существующий экземпляр.

Может ли кто-нибудь увидеть, что не так с моим кодом? Как мне использовать EventWaitHandle для нескольких одновременных пользовательских сеансов на одном компьютере?


person dumbledad    schedule 08.08.2012    source источник
comment
Объект события здесь не подходит, он страдает от неразрешимого состояния гонки. Использование Mutex является шаблонным, у него есть конструктор, который возвращает логическое значение createdNew, которое сообщает вам, что ваш процесс попал туда первым.   -  person Hans Passant    schedule 08.08.2012
comment
Спасибо, Ханс, интересно. Я думаю, что в этом случае я относительно защищен от условий гонки, поскольку механизмы, с помощью которых может запуститься второе приложение, требуют времени. Я начал использовать два мьютекса, но переключился на события, я изучу еще кое-что.   -  person dumbledad    schedule 08.08.2012


Ответы (1)


Разве не всегда так: через несколько минут после написания длинного вопроса в голову приходит ответ!

Я неправильно поставил косую черту в имени EventWaitHandle. Например, замена вызова конструктора:

new EventWaitHandle(false, EventResetMode.AutoReset, "Global/AaltoTokensAppShutdownEvent", out createdShutdown, security)

с этим:

new EventWaitHandle(false, EventResetMode.AutoReset, @"Global\AaltoTokensAppShutdownEvent", out createdShutdown, security)

исправляет мою проблему.

person dumbledad    schedule 08.08.2012