(no subject)

Jul 02, 2012 15:45

Иногда нужно, что бы программа была запущена лишь в одном экземпляре.
Обычно (Win32) в таких случаях при запуске программы пытаются создать мьютекс, и если он уже существует, значит уже выполняется другая копия этой программы. Если же мьютекс удаётся создать, значит программа запущена в единственном экземпляре.
После выполнения нужной работы мьютекс уничтожается.

На сях это выглядит примерно так:

#include
#include
#include

const char *MutexName = "TestMutex";

int main(int argc, char *argv[])
{
HANDLE hMutex = CreateMutexA(0, 0, MutexName);
if (GetLastError() != ERROR_ALREADY_EXISTS &&
GetLastError() != ERROR_ACCESS_DENIED)
{
printf("Hello, world\n");
getch();

ReleaseMutex(hMutex);
}
return 0;
}
На хаскелле же это может выглядеть так:


module Main where

import Control.Monad
import qualified Graphics.Win32 as W32
import Foreign.C.String

--------------------------------------------------------------------------------

mutexName = "TestMutex"

main = withMutex mutexName $ do
putStrLn "Hello, world"
getChar
return ()

--------------------------------------------------------------------------------
-- Создаёт мьютекс с именем mutexName
-- Если мьютекс создан успешно, выполняет действие action
-- После завершения действия action мьютекс уничтожается
--
withMutex :: String -> IO () -> IO ()
withMutex mutexName action = do
withCString mutexName $ \c_mutexName -> do
mHandle <- c_CreateMutex 0 0 c_mutexName
lastErr <- c_GetLastError
let exists = lastErr == eRROR_ALREADY_EXISTS ||
lastErr == eRROR_ACCESS_DENIED
when (not exists) $ do
action
c_ReleaseMutex mHandle
return ()

--------------------------------------------------------------------------------
-- Cannot create a file when that file already exists
--
eRROR_ALREADY_EXISTS :: W32.DWORD
eRROR_ALREADY_EXISTS = 183

eRROR_ACCESS_DENIED :: W32.DWORD
eRROR_ACCESS_DENIED = 5

--------------------------------------------------------------------------------

foreign import stdcall unsafe "CreateMutexA"
c_CreateMutex :: W32.INT -> W32.INT -> CString -> IO W32.HANDLE

foreign import stdcall unsafe "ReleaseMutex"
c_ReleaseMutex :: W32.HANDLE -> IO W32.BOOL

foreign import stdcall unsafe "GetLastError"
c_GetLastError :: IO W32.DWORD

ЗЫ. Может, кто знает, как делать такие вещи более правильно, в хаскель-вее?

ЗЗЫ. Кстати, ссылка по теме: http://www.rsdn.ru/article/baseserv/avins.xml
Previous post Next post
Up