प्रोसेस सिंक्रोनाइज़ेशन साझा डेटा तक समवर्ती पहुंच की समस्या को दूर करने की तकनीक है जिसके परिणामस्वरूप डेटा असंगति हो सकती है। एक सहयोगी प्रक्रिया वह है जो अन्य प्रक्रिया को प्रभावित कर सकती है या उससे प्रभावित हो सकती है जिससे प्रक्रियाओं के डेटा में असंगति आ जाएगी इसलिए डेटा की स्थिरता के लिए प्रोसेस सिंक्रोनाइज़ेशन आवश्यक है।
क्रिटिकल-सेक्शन समस्या (The Critical-Section Problem)
प्रत्येक प्रक्रिया के पास कोड का एक आरक्षित खंड होता जिसे क्रिटिकल सेक्शन के रूप में जाना जाता है। इस खंड में, प्रक्रिया सामान्य वेरिएबल्स को बदल सकती है, टेबल अपडेट कर सकती है, फाइल लिख सकती है, आदि। क्रिटिकल सेक्शन के बारे में ध्यान देने योग्य मुख्य बिंदु यह है कि जब एक प्रक्रिया अपने क्रिटिकल सेक्शन में निष्पादित हो रही होती है, तो कोई अन्य प्रक्रिया अपने क्रिटिकल सेक्शन में निष्पादित नहीं हो सकती। प्रत्येक प्रक्रिया को अपने क्रिटिकल सेक्शन में प्रवेश करने से पहले अनुमति का अनुरोध करना होगा और इस अनुरोध को लागू करने वाले कोड का खंड एंट्री सेक्शन है, कोड का अंत एग्जिट सेक्शन है और शेष कोड रिमेनडर सेक्शन है।
नीचे एक विशेष प्रक्रिया P1 के क्रिटिकल सेक्शन की संरचना दी गई है

क्रिटिकल सेक्शन के लिए तीन आवश्यकताएं हैं जिन्हें पूरा किया जाना चाहिए
- म्यूचुअल एक्सक्लूजन (Mutual Exclusion) - यदि एक प्रक्रिया मान लें P1 अपने क्रिटिकल सेक्शन में निष्पादित हो रही है तो कोई अन्य प्रक्रिया मान लें P2 अपने क्रिटिकल सेक्शन में निष्पादित नहीं हो सकती।
- प्रोग्रेस (Progress) - यदि कोई प्रक्रिया अपने क्रिटिकल सेक्शन में निष्पादित नहीं हो रही है और ऐसी प्रक्रियाएं हैं जो अपने क्रिटिकल सेक्शन में प्रवेश करना चाहती हैं, तो केवल वे प्रक्रियाएं जो अपने रिमेनडर सेक्शन में निष्पादित नहीं हो रही हैं, क्रिटिकल सेक्शन में प्रवेश करने का अनुरोध कर सकती हैं और चयन को अनिश्चित काल के लिए स्थगित किया जा सकता है।
- बाउंडेड वेटिंग (Bounded Waiting) - बाउंडेड वेटिंग में, एक प्रक्रिया द्वारा अपने क्रिटिकल सेक्शन में प्रवेश करने का अनुरोध करने के बाद और उस अनुरोध के दिए जाने से पहले एक प्रक्रिया अपने क्रिटिकल सेक्शन में प्रवेश करने की संख्या पर सीमाएं या बाउंड होते हैं।
ऑपरेटिंग सिस्टम में क्रिटिकल सेक्शन को संभालने के लिए दो दृष्टिकोण आमतौर पर उपयोग किए जाते हैं।
प्रीमेप्टिव कर्नेल (Preemptive Kernel) - एक प्रीमेप्टिव कर्नेल एक प्रक्रिया को कर्नेल मोड में चलते समय प्रीमेप्ट करने की अनुमति देता है।
नॉन-प्रीमेप्टिव कर्नेल (Non-Preemptive Kernels) - एक नॉन-प्रीमेप्टिव कर्नेल कर्नेल मोड में चल रही प्रक्रिया को प्रीमेप्ट करने की अनुमति नहीं देता।
पीटरसन का समाधान (Peterson's Solution)
पीटरसन का समाधान क्रिटिकल-सेक्शन समस्या का एक क्लासिक सॉफ्टवेयर-आधारित समाधान है। यह दो प्रक्रियाओं तक सीमित है जो अपने क्रिटिकल सेक्शन और रिमेनडर सेक्शन के बीच निष्पादन को वैकल्पिक रूप से करते हैं। पीटरसन के समाधान में दो प्रक्रियाओं के बीच साझा किए जाने वाले दो डेटा आइटम की आवश्यकता होती है यानी
- int turn;
- boolean flag[2];
यहां, वेरिएबल turn इंगित करता है कि किसकी बारी है अपने क्रिटिकल सेक्शन में प्रवेश करने की और फ्लैग ऐरे इंगित करता है कि प्रक्रिया अपने क्रिटिकल सेक्शन में प्रवेश करने के लिए तैयार है या नहीं।
यदि turn == i, तो इसका मतलब है कि प्रक्रिया Pi को अपने क्रिटिकल सेक्शन में प्रवेश करने की अनुमति है।
यदि flag[j] TRUE है, तो इसका मतलब है कि प्रक्रिया j अपने क्रिटिकल सेक्शन में प्रवेश करने के लिए तैयार है।
नीचे पीटरसन के समाधान में प्रक्रिया P की संरचना दी गई है

पीटरसन का समाधान सभी तीन शर्तों को संरक्षित करता है -
- म्यूचुअल एक्सक्लूजन - एक समय में एक प्रक्रिया क्रिटिकल सेक्शन तक पहुंच सकती है।
- प्रोग्रेस - क्रिटिकल सेक्शन के बाहर की प्रक्रिया अन्य प्रक्रियाओं को क्रिटिकल सेक्शन में प्रवेश करने से नहीं रोकती।
- बाउंडेड वेटिंग - प्रत्येक प्रक्रिया को अनिश्चित काल तक इंतजार किए बिना अपने क्रिटिकल सेक्शन में प्रवेश करने का मौका मिलेगा।
सिंक्रोनाइज़ेशन हार्डवेयर (Synchronization Hardware)
यह दो प्रकार के निर्देशों का उपयोग करके लागू किया जाता है -
- Test and Set()
- swap()
Test and Set () सिंक्रोनाइज़ेशन की समस्या को हल करने के लिए एक हार्डवेयर समाधान है। इसमें एक साझा वेरिएबल होता है जिसे कई प्रक्रियाओं द्वारा साझा किया जाता है जिसे Lock के नाम से जाना जाता है जिसके 0 और 1 से एक मान हो सकता है जहां 1 लॉक प्राप्त होने को दर्शाता है और 0 लॉक जारी होने को दर्शाता है।
जब भी प्रक्रिया अपने क्रिटिकल सेक्शन में प्रवेश करने का प्रयास करती है तो उन्हें लॉक के मान के बारे में पूछताछ करने की आवश्यकता होती है। यदि लॉक का मान 1 है तो उन्हें तब तक इंतजार करना होगा जब तक लॉक का मान 0 नहीं हो जाता।
नीचे TestAndSet() के साथ म्यूचुअल-एक्सक्लूजन कार्यान्वयन दिया गया है

सेमाफोर्स (Semaphores)
सेमाफोर एक सिंक्रोनाइज़ेशन टूल है जिसका उपयोग TestAndSet() और Swap() निर्देशों द्वारा उत्पन्न समस्याओं को दूर करने के लिए किया जाता है। एक सेमाफोर S एक पूर्णांक वेरिएबल है जिसे दो मानक एटॉमिक ऑपरेशन्स के माध्यम से एक्सेस किया जा सकता है जो wait() और signal() हैं।
wait() के लिए फंक्शन:
wait(S) {
While S <= 0
; // no operation
S--;
}
Signal() के लिए फंक्शन:
signal(S) {
S++;
}
जब एक प्रक्रिया सेमाफोर के मान को संशोधित कर रही होती है तो कोई अन्य प्रक्रिया एक साथ उसी सेमाफोर मान में हेरफेर नहीं कर सकती।
नीचे सेमाफोर के साथ म्यूचुअल-एक्सक्लूजन कार्यान्वयन दिया गया है

ऑपरेटिंग सिस्टम दो प्रकार के सेमाफोर्स का उपयोग करता है जो हैं -
काउंटिंग सेमाफोर (Counting Semaphore) - इस प्रकार के सेमाफोर का मान एक अप्रतिबंधित डोमेन पर हो सकता है।
बाइनरी सेमाफोर (Binary Semaphore) - इस प्रकार के सेमाफोर का मान 0 और 1 के बीच हो सकता है। इन्हें म्यूटेक्स लॉक्स के रूप में भी जाना जाता है। ऑपरेटिंग सिस्टम बहु-प्रक्रियाओं में क्रिटिकल सेक्शन के मुद्दों को हल करने के लिए इसका उपयोग करता है।