mirror of
https://github.com/SantaSpeen/winmutex.git
synced 2025-07-03 00:15:26 +00:00
[!] Ready?
This commit is contained in:
parent
b4fafbf5f0
commit
474bcdee5a
51
README.md
Normal file
51
README.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# pywinmutex
|
||||||
|
|
||||||
|
A simple Python library to create and manage Windows mutexes.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
You can install the library using pip:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install pywinmutex
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Example
|
||||||
|
```python
|
||||||
|
from pywinmutex import WindowsMutex
|
||||||
|
|
||||||
|
mutex = WindowsMutex("anidev/pywinmutex/simple", True) # Name may be any string
|
||||||
|
mutex.timeout = 2500 # Set a timeout of 2.5 seconds
|
||||||
|
|
||||||
|
with mutex:
|
||||||
|
print(f"[I] Mutex({mutex}) acquired.")
|
||||||
|
input("Enter to release the mutex and exit> ")
|
||||||
|
|
||||||
|
print(f"[I] Mutex({mutex}) released. Exiting...")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Legacy
|
||||||
|
```python
|
||||||
|
from pywinmutex import WindowsMutex
|
||||||
|
|
||||||
|
mutex = WindowsMutex("anidev/pywinmutex/acquire", True) # Name may be any string
|
||||||
|
|
||||||
|
if not mutex.acquire(5000): # Acquire the mutex with a timeout of 5 seconds; None for no timeout
|
||||||
|
print(f"[W] Mutex({mutex}) already exists or acquire timeout exceeded.")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Do some work while holding the mutex
|
||||||
|
|
||||||
|
print(f"[I] Mutex({mutex}) acquired.")
|
||||||
|
input("Enter to release the mutex and exit> ")
|
||||||
|
|
||||||
|
# Release the mutex
|
||||||
|
mutex.release()
|
||||||
|
print(f"[I] Mutex({mutex}) released. Exiting...")
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the `MIT License`. See the [LICENSE](LICENSE) file for details.
|
135
pywinmutex/__init__.py
Normal file
135
pywinmutex/__init__.py
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import threading
|
||||||
|
|
||||||
|
import win32event
|
||||||
|
import win32api
|
||||||
|
import winerror
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
class WindowsMutex:
|
||||||
|
def __init__(self, name, multiuser=False, timeout=None):
|
||||||
|
"""
|
||||||
|
Initialize the WindowsMutex object.
|
||||||
|
:param name: Name of the mutex.
|
||||||
|
:param multiuser: If True, create a local mutex; if False, create a global mutex (Shared across all users).
|
||||||
|
"""
|
||||||
|
self.__multiuser = multiuser
|
||||||
|
self._friendly_name = name
|
||||||
|
__global_prefix = "Global\\" if multiuser else ""
|
||||||
|
self._mutex_name = f"{__global_prefix}{name}"
|
||||||
|
self._handler = None
|
||||||
|
self._exist = False
|
||||||
|
self._th_lock = threading.Lock()
|
||||||
|
self.timeout = timeout
|
||||||
|
atexit.register(self.release)
|
||||||
|
|
||||||
|
def __try_to_lock(self):
|
||||||
|
"""
|
||||||
|
Try to acquire the mutex.
|
||||||
|
:return: True if the mutex was acquired, False otherwise.
|
||||||
|
"""
|
||||||
|
with self._th_lock: # Thread-safe access
|
||||||
|
handler = win32event.CreateMutex(None, False, self._mutex_name)
|
||||||
|
if handler is None:
|
||||||
|
raise RuntimeError("Failed to create mutex.")
|
||||||
|
exist = win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS
|
||||||
|
if not exist:
|
||||||
|
win32api.CloseHandle(handler)
|
||||||
|
return exist
|
||||||
|
|
||||||
|
def reinint(self, name, multiuser=None):
|
||||||
|
"""
|
||||||
|
Reinitialize the mutex with a new name.
|
||||||
|
:param name: New name for the mutex.
|
||||||
|
:param local: If True, create a local mutex; if False, create a global mutex.
|
||||||
|
"""
|
||||||
|
self.release()
|
||||||
|
if multiuser is None:
|
||||||
|
multiuser = self.__multiuser
|
||||||
|
self.__init__(name, multiuser)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def settings(self):
|
||||||
|
"""
|
||||||
|
Get the settings of the mutex.
|
||||||
|
:return: A dictionary containing the mutex name and existence status.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"name": self._mutex_name,
|
||||||
|
"exist": self.exist
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exist(self):
|
||||||
|
"""
|
||||||
|
Check if the mutex already exists.
|
||||||
|
:return: True if the mutex exists, False otherwise.
|
||||||
|
"""
|
||||||
|
if self._handler is None:
|
||||||
|
return self.__try_to_lock()
|
||||||
|
return self._exist
|
||||||
|
|
||||||
|
def _lock(self):
|
||||||
|
"""
|
||||||
|
Try to lock the mutex.
|
||||||
|
:return: True if acquired, False otherwise.
|
||||||
|
"""
|
||||||
|
with self._th_lock: # Thread-safe access
|
||||||
|
if self._handler is None: # Создаём мутекс только один раз
|
||||||
|
self._handler = win32event.CreateMutex(None, False, self._mutex_name)
|
||||||
|
self._exist = win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS
|
||||||
|
return not self._exist # True, если удалось захватить мутекс
|
||||||
|
return False # Если мутекс уже создан, значит, его кто-то держит
|
||||||
|
|
||||||
|
def acquire(self, timeout=None, __raw_result=False):
|
||||||
|
"""
|
||||||
|
Wait until the mutex is acquired.
|
||||||
|
:param timeout: Timeout in milliseconds. If None, waits indefinitely.
|
||||||
|
:param __raw_result: If True, return the raw result of WaitForSingleObject.
|
||||||
|
:return: True if acquired, False if timeout.
|
||||||
|
"""
|
||||||
|
if self._handler is None:
|
||||||
|
self._lock()
|
||||||
|
|
||||||
|
wait_time = timeout if timeout is not None else win32event.INFINITE
|
||||||
|
result = win32event.WaitForSingleObject(self._handler, wait_time)
|
||||||
|
|
||||||
|
if result != win32event.WAIT_OBJECT_0:
|
||||||
|
self._handler = None
|
||||||
|
self._exist = False
|
||||||
|
|
||||||
|
if __raw_result:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result == win32event.WAIT_OBJECT_0
|
||||||
|
|
||||||
|
def release(self):
|
||||||
|
"""
|
||||||
|
Release the mutex.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
with self._th_lock: # Thread-safe access
|
||||||
|
if self._handler:
|
||||||
|
win32event.ReleaseMutex(self._handler)
|
||||||
|
win32api.CloseHandle(self._handler) # Закрываем _handler!
|
||||||
|
self._handler = None
|
||||||
|
self._exist = False
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
reason = self.acquire(self.timeout, True)
|
||||||
|
if reason == win32event.WAIT_OBJECT_0:
|
||||||
|
return self
|
||||||
|
elif reason == win32event.WAIT_TIMEOUT:
|
||||||
|
raise TimeoutError("Mutex acquisition timed out.")
|
||||||
|
elif reason == win32event.WAIT_ABANDONED:
|
||||||
|
raise RuntimeError("Mutex was abandoned.")
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Failed to acquire mutex.")
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
self.release()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self!r}"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<WindowsMutex(name={self._friendly_name!r}, multiuser={self.__multiuser})>"
|
Loading…
x
Reference in New Issue
Block a user