تزامن العمليات والخيوط
مقدمة
عندما تصل عدة خيوط أو عمليات إلى موارد مشتركة، يجب تنسيق وصولها لتجنب مشاكل التنافس.
مشاكل التنافس
Race Condition (شرط السباق)
عندما يعتمد النتيجة على ترتيب تنفيذ غير محدد.
Thread 1 Thread 2
-------- --------
Lire compteur (= 5)
Lire compteur (= 5)
Incrementer (= 6)
Incrementer (= 6)
Ecrire (= 6)
Ecrire (= 6)
Resultat: 6 au lieu de 7!
Section Critique
منطقة من الكود تصل إلى مورد مشترك ويجب تنفيذها بواسطة خيط واحد فقط في كل مرة.
Deadlock (توقف)
حالة حيث ينتظر خيطان بعضهما البعض إلى ما لا نهاية.
Thread 1: Detient A, attend B
Thread 2: Detient B, attend A
-> Blocage permanent!
آليات التزامن في Windows
نظرة عامة
| Mecanisme | Portee | Utilisation |
|---|---|---|
| Critical Section | Intra-processus | وصول سريع، نفس العملية |
| Mutex | Inter-processus | استبعاد متبادل، مسمى |
| Semaphore | Inter-processus | التحكم في الوصول المتعدد |
| Event | Inter-processus | الإشارة |
| Interlocked | Intra-processus | عمليات ذرية بسيطة |
Critical Section
المفهوم
آلية خفيفة لتزامن الخيوط داخل نفس العملية.
الخصائص
- أسرع من Mutex
- محدود بعملية واحدة
- غير مسمى
الاستخدام (C/C++)
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
// Section critique - un seul thread a la fois
compteur++;
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
في PowerShell (محاكاة)
# Utilisation de [System.Threading.Monitor]
$lockObj = New-Object Object
$compteur = 0
[System.Threading.Monitor]::Enter($lockObj)
try {
# Section critique
$compteur++
}
finally {
[System.Threading.Monitor]::Exit($lockObj)
}
Mutex (الاستبعاد المتبادل)
المفهوم
كائن تزامن يسمح بالاستبعاد المتبادل بين العمليات.
الخصائص
- يمكن أن يكون مسمى (متاح بين العمليات)
- أبطأ من Critical Section
- إمكانية اكتشاف التوقف
الاستخدام في PowerShell
# Creer ou ouvrir un mutex nomme
$mutexName = "Global\MonMutex"
$mutex = New-Object System.Threading.Mutex($false, $mutexName)
try {
# Attendre le mutex (timeout 5 secondes)
if ($mutex.WaitOne(5000)) {
try {
Write-Host "Mutex acquis - section critique"
# Travail exclusif ici
Start-Sleep -Seconds 2
}
finally {
$mutex.ReleaseMutex()
Write-Host "Mutex libere"
}
}
else {
Write-Host "Timeout - mutex non acquis"
}
}
finally {
$mutex.Close()
}
Mutex مسمى مقابل غير مسمى
| Type | Nom | Portee |
|---|---|---|
| Anonyme | Aucun | Threads du meme processus |
| Local | "Local\Nom" | Session utilisateur |
| Global | "Global\Nom" | Tous les processus systeme |
Semaphore
المفهوم
يسمح بتحديد عدد الوصولات المتزامنة إلى مورد.
الفرق مع Mutex
| Mutex | Semaphore |
|---|---|
| 1 seul acces | N acces simultanees |
| Proprietaire unique | Pas de proprietaire |
الاستخدام في PowerShell
# Semaphore avec 3 places
$semName = "Global\MonSemaphore"
$semaphore = New-Object System.Threading.Semaphore(3, 3, $semName)
try {
if ($semaphore.WaitOne(5000)) {
try {
Write-Host "Place acquise dans le semaphore"
# Travail limite a 3 threads simultanees
Start-Sleep -Seconds 2
}
finally {
$semaphore.Release()
Write-Host "Place liberee"
}
}
}
finally {
$semaphore.Close()
}
حالات الاستخدام
- مجموعة اتصالات قاعدة البيانات
- تحديد التنزيلات المتزامنة
- التحكم في الموارد المحدودة
Event
المفهوم
يسمح لخيط بالإشارة إلى حدث لخيوط أخرى.
أنواع الأحداث
| Type | Comportement |
|---|---|
| AutoReset | Libere un seul thread puis se remet a non-signale |
| ManualReset | Reste signale jusqu'a reset explicite |
الاستخدام في PowerShell
# Event ManualReset
$eventName = "Global\MonEvent"
$event = New-Object System.Threading.EventWaitHandle(
$false, # Initial state: non signale
[System.Threading.EventResetMode]::ManualReset,
$eventName
)
# Dans le thread producteur
$event.Set() # Signaler
$event.Reset() # Remettre a non signale
# Dans le thread consommateur
if ($event.WaitOne(5000)) {
Write-Host "Event recu!"
}
$event.Close()
Interlocked Operations
المفهوم
عمليات ذرية على المتغيرات، دون الحاجة إلى قفل صريح.
العمليات المتاحة
| Operation | Description |
|---|---|
| Increment | Incremente de 1 |
| Decrement | Decremente de 1 |
| Add | Ajoute une valeur |
| Exchange | Echange des valeurs |
| CompareExchange | Echange conditionnel |
الاستخدام في PowerShell
# Increment atomique
$compteur = 0
[System.Threading.Interlocked]::Increment([ref]$compteur)
Write-Host "Compteur: $compteur"
# Add atomique
[System.Threading.Interlocked]::Add([ref]$compteur, 10)
Write-Host "Compteur apres add: $compteur"
# Exchange atomique
$oldValue = [System.Threading.Interlocked]::Exchange([ref]$compteur, 100)
Write-Host "Ancienne valeur: $oldValue, Nouvelle: $compteur"
الممارسات الجيدة
تجنب التوقفات
- ترتيب ثابت: احصل دائمًا على الأقفال بنفس الترتيب
- Timeouts: استخدم timeouts لاكتشاف التوقفات
- التقليل: حافظ على الأقسام الحرجة قصيرة
مثال على تجنب التوقف
# MAUVAIS - risque de deadlock
# Thread 1: Lock A puis Lock B
# Thread 2: Lock B puis Lock A
# BON - ordre constant
# Thread 1: Lock A puis Lock B
# Thread 2: Lock A puis Lock B (meme ordre!)
الأداء
| Mecanisme | Performance | Cas d'usage |
|---|---|---|
| Interlocked | Tres rapide | Operations simples |
| Critical Section | Rapide | Meme processus |
| Mutex | Moyen | Inter-processus |
| Semaphore | Moyen | Acces multiple limite |
اكتشاف المشاكل
Process Explorer
- View > Show Lower Pane
- Handle view: voir les handles de synchronisation
WinDbg
!locks # Afficher les locks
!handle # Afficher les handles
!analyze -hang # Analyser un hang/deadlock
Performance Monitor
المؤشرات المفيدة:
Process > Handle CountThread > Context Switches/sec
التمارين
- قم بإنشاء سكربت مع وظيفتين PowerShell تستخدمان mutex مشترك
- قم بتنفيذ عداد آمن للخيوط باستخدام Interlocked
- قم بإنشاء semaphore يقتصر على تنفيذين متزامنين