Как убедиться, что CreateProcess создает только один процесс при одновременном вызове в c ++? - PullRequest
2 голосов
/ 22 августа 2010

Цитируется здесь :

BOOL WINAPI CreateProcess(
  __in_opt     LPCTSTR lpApplicationName,
  __inout_opt  LPTSTR lpCommandLine,
  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in         BOOL bInheritHandles,
  __in         DWORD dwCreationFlags,
  __in_opt     LPVOID lpEnvironment,
  __in_opt     LPCTSTR lpCurrentDirectory,
  __in         LPSTARTUPINFO lpStartupInfo,
  __out        LPPROCESS_INFORMATION lpProcessInformation
);

У меня есть две независимые программы, которые создают точно такой же процесс, как я могу гарантировать, что если один из них имеетуже создал процесс, другой не создаст его дважды?

Ответы [ 3 ]

4 голосов
/ 22 августа 2010

Самый простой способ - создать именованный объект после запуска программы.Например CreateEvent , CreateMutex и так далее.Для проверки существования приложения вы можете просто использовать OpenEvent , OpenMutex и т. Д. Перед созданием объекта.Вы можете выбрать (при желании) имя объекта с префиксом «Global \» (см. http://msdn.microsoft.com/en-us/library/aa382954.aspx), чтобы разрешить только один процесс для всего сеанса сервера терминалов.

ОБНОВЛЕНО : Поскольку, как я вижу, существуют разные мнения по поводу моего предложения, я пытаюсь объяснить его более точно и добавить соответствующий тестовый пример.

Основная идея заключается в том, что приложение, которое запускается, создает любое именованный объект - это объект с тем же именем, которого еще нет. Это зарезервирует имя только в пространствах имен объектов ядра . Реальное использование объекта не требуется. Преимущество этого способа по сравнению с созданиемфайла на диске состоит в том, что именованные объекты временные и принадлежат приложению . Таким образом, если приложение завершено, оно будет уничтожено или завершено любым другим способом (из-занапример, исключение в произвольном порядке) именованный объект будет автоматически удален операционной системой. В следующем примере я неиспользуйте CloseHandle на всех.То, как вы можете протестировать приложение, может успешно определить, работает ли оно как первый экземпляр или нет.

#include <windows.h>
//#include <Sddl.h>

LPCTSTR g_pszEventName = TEXT("MyTestEvent"); // TEXT("Global\\MyTestEvent")

void DisplayFirstInstanceStartedMessage()
{
    TCHAR szText[1024];
    wsprintf (szText,
        TEXT("The first instance are started.\nThe event with the name \"%s\" is created."),
        g_pszEventName);

    MessageBox (NULL,
        szText,
        TEXT("CreateEventTest"), MB_OK);
}

void DisplayAlreadyRunningMessage ()
{
    TCHAR szText[1024];
    wsprintf (szText,
        TEXT("The first instance of the aplication is already running.\nThe event with the name \"%s\" already exist."),
        g_pszEventName);

    MessageBox (NULL,
        szText,
        TEXT("CreateEventTest"), MB_ICONWARNING | MB_OK);
}

void DisplayErrorMessage (DWORD dwErrorCode)
{
    if (dwErrorCode == ERROR_ALREADY_EXISTS)
        DisplayAlreadyRunningMessage();
    else {
        LPTSTR  pErrorString;
        if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |    // Always search in system message table !!!
                            FORMAT_MESSAGE_ALLOCATE_BUFFER |
                            FORMAT_MESSAGE_IGNORE_INSERTS |
                            0, NULL,                // source of message definition
                            dwErrorCode,            // message ID
    //                        0,                      // language ID
    //                        GetUserDefaultLangID(), // language ID
    //                        GetSystemDefaultLangID(),
                            MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
                            (LPTSTR)&pErrorString,   // pointer for buffer to allocate
                            0,                      // min number of chars to allocate
                            NULL)) {
            MessageBox (NULL, pErrorString, TEXT("CreateEventTest"), MB_OK);
            LocalFree (pErrorString);
        }
        else {
            TCHAR szText[1024];
            wsprintf (szText, TEXT("Error %d in the CreateEvent(..., \"%s\")"), dwErrorCode, g_pszEventName);
            MessageBox (NULL, szText, TEXT("CreateEventTest"), MB_OK);
        }
    }
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //SECURITY_ATTRIBUTES sa;
    //BOOL bSuccess;
    HANDLE hEvent = OpenEvent (EVENT_MODIFY_STATE, FALSE, g_pszEventName);// EVENT_ALL_ACCESS
    if (hEvent == NULL) {
        DWORD dwErrorCode = GetLastError();
        if (dwErrorCode != ERROR_FILE_NOT_FOUND) {
            DisplayErrorMessage(dwErrorCode);
            return 1;
        }
    }
    else {
        DisplayAlreadyRunningMessage();
        return 0;
    }

    //sa.bInheritHandle = FALSE;
    //sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    //bSuccess = ConvertStringSecurityDescriptorToSecurityDescriptor (
    //    TEXT("D:(A;OICI;GA;;;WD)"),    // Allow full control 
    //    SDDL_REVISION_1,
    //    &sa.lpSecurityDescriptor,
    //    NULL);
    hEvent = CreateEvent (NULL, // &sa
        TRUE, FALSE, g_pszEventName);
    //sa.lpSecurityDescriptor = LocalFree (sa.lpSecurityDescriptor);
    if (hEvent == NULL) {
        DWORD dwErrorCode = GetLastError();
        DisplayErrorMessage(dwErrorCode);
        return 1;
    }
    else
        DisplayFirstInstanceStartedMessage();

    return 0;
    UNREFERENCED_PARAMETER (hInstance);
    UNREFERENCED_PARAMETER (hPrevInstance);
    UNREFERENCED_PARAMETER (lpCmdLine);
    UNREFERENCED_PARAMETER (nShowCmd);
}

Если требуется поддержка, чтобы разные пользователи с одного и того же рабочего стола или с разных рабочих столов могли запустить только один экземплярВ программе можно раскомментировать некоторые части закомментированного кода или заменить имя MyTestEvent события на Global\MyTestEvent.

Надеюсь, после примера моя позиция будет ясна.При использовании такого типа событий вызов WaitForSingleObject() не требуется.

2 голосов
/ 22 августа 2010

Вы не можете сделать это, позволив процессу начать создавать именованный объект.Это неотъемлемое условие гонки, для начала процесса требуется время.Обе программы должны вызвать CreateMutex в какой-то момент, прежде чем пытаться создать 3-й процесс с согласованным именем.Затем им нужно вызвать WaitForSingleObject () с нулевым временем ожидания, чтобы попытаться получить мьютекс.Кто бы ни получил это, тот должен вызывать CreateProcess ().

После этого требуется больше работы, чтобы завершить этот третий процесс.

0 голосов
/ 22 августа 2010

Вы можете использовать эту функцию

BOOL WINAPI EnumProcesses (__out DWORD * pProcessIds, __in DWORD cb, __out DWORD * pBytesReturned);

для получения спискавсе pids всех запущенных в данный момент процессов и проверьте, запущен ли процесс?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...