Windows operatsion tizimida iplarni sinxronlash vositalari (muhim bo'limlar, mutekslar, semaforlar, hodisalar). Windowsda sinxronlash ob'ektlari Hodisalar yordamida jarayonlarni sinxronlash

Ma'ruza № 9. Jarayonlar va iplarni sinxronlashtirish

1. Sinxronizatsiyaning maqsadi va vositalari.

2. Sinxronizatsiya mexanizmlari.

1.Sinxronizatsiyaning maqsadi va vositalari

Jarayonlar va oqimlarning o'zaro sinxronizatsiyasini ta'minlaydigan operatsion tizim vositalarining etarlicha keng sinfi mavjud. Iplarni sinxronlashtirish zarurati faqat ko'p dasturli operatsion tizimda paydo bo'ladi va kompyuter tizimining apparat va axborot resurslaridan birgalikda foydalanish bilan bog'liq. Sinxronizatsiya iplar o'rtasida ma'lumot almashish, ma'lumotlarni almashish va protsessor va kiritish-chiqarish qurilmalariga kirishda poygalar va blokirovkalarni oldini olish uchun zarur.

Ko'pgina operatsion tizimlarda ushbu vositalar jarayonlararo aloqa vositalari (IPC) deb ataladi, bu "jarayon" tushunchasining "ip" tushunchasiga nisbatan tarixiy ustuvorligini aks ettiradi. Odatda, IPC vositalari nafaqat jarayonlararo sinxronizatsiya vositalarini, balki jarayonlararo ma'lumotlarni almashish vositalarini ham o'z ichiga oladi.

Ko'p dasturlash muhitida ipning bajarilishi har doim asinxrondir. Jarayonning ma'lum bir vaqtida bajarilishining qaysi bosqichida bo'lishini to'liq ishonch bilan aytish juda qiyin. Hatto bitta dasturli rejimda ham vazifani bajarish uchun zarur bo'lgan vaqtni to'g'ri baholash har doim ham mumkin emas. Bu vaqt ko'p hollarda sezilarli darajada manba ma'lumotlarining qiymatiga bog'liq bo'lib, u tsikllar soniga, dasturning tarmoqlanish yo'nalishiga, kiritish-chiqarish operatsiyalarini bajarish vaqtiga va hokazolarga ta'sir qiladi. ishga tushirilgan har xil bo'lishi mumkin, shuning uchun ijro vaqti individual bosqichlari va bir butun sifatida vazifa juda noaniq qiymati bo'lishi mumkin.


Ko'p dasturlash tizimida dasturning bajarilish vaqti yanada noaniq. Mavzular uzilib qolgan lahzalar, ularning umumiy resurslar uchun navbatda turishi, bajarish uchun iplarni tanlash tartibi - bularning barchasi ko'plab holatlarning birlashishi natijasidir va ularni tasodifiy deb talqin qilish mumkin. Eng yaxshi holatda, hisoblash jarayonining ehtimollik xarakteristikalarini, masalan, ma'lum vaqt oralig'ida uning tugash ehtimolini taxmin qilish mumkin.

Shunday qilib, umumiy holatda (dasturchi ularni sinxronlashtirish uchun maxsus choralar ko'rmagan bo'lsa) iplar mustaqil ravishda, bir-biri bilan asinxron ravishda oqadi. Bu umumiy dastur kodini bajaradigan bir jarayondagi iplar uchun ham, har biri o'z dasturini bajaradigan turli jarayonlardagi iplar uchun ham amal qiladi.

Jarayonlar yoki oqimlar o'rtasidagi har qanday o'zaro ta'sir ular bilan bog'liq sinxronizatsiya, ma'lum bir hodisa sodir bo'lgunga qadar oqimni to'xtatib turish va keyin bu hodisa sodir bo'lganda uni faollashtirish orqali ularning tezligini muvofiqlashtirishdan iborat. Sinxronizatsiya resurs almashish yoki ma'lumotlar almashinuvini o'z ichiga oladimi, har qanday o'zaro ta'sirning asosini tashkil qiladi. Misol uchun, qabul qiluvchi ip ma'lumotlarga faqat jo'natuvchi ip tomonidan buferlanganidan keyin kirishi kerak. Agar qabul qiluvchi ip buferga kirishdan oldin ma'lumotlarga kirgan bo'lsa, u to'xtatilishi kerak.

Uskuna resurslarini baham ko'rishda sinxronizatsiya ham mutlaqo zarur. Masalan, agar faol ip ketma-ket portga kirishi kerak bo'lsa va hozirda kutish holatida bo'lgan boshqa ip ushbu port bilan eksklyuziv rejimda ishlayotgan bo'lsa, OT faol ipni to'xtatib qo'yadi va kerakli portgacha uni faollashtirmaydi. bepul. Kompyuter tizimidan tashqaridagi hodisalar bilan sinxronlash, masalan, Ctrl + C tugmalar birikmasini bosish reaktsiyasi ham ko'pincha zarur.

Har soniyada tizimda resurslarni taqsimlash va chiqarish bilan bog'liq yuzlab hodisalar ro'y beradi va OT tizimda sodir bo'layotgan voqealar bilan oqimlarni sinxronlashtirishga imkon beradigan ishonchli va samarali vositalarga ega bo'lishi kerak.

Ilova dasturlari iplarini sinxronlashtirish uchun dasturchi o'zining sinxronlash vositalari va texnikasidan ham, operatsion tizim vositalaridan ham foydalanishi mumkin. Misol uchun, bir xil dastur jarayonining ikkita ipi ikkalasi uchun ham mavjud bo'lgan global mantiqiy o'zgaruvchidan foydalangan holda o'z ishlarini muvofiqlashtirishi mumkin, bu ba'zi bir voqea sodir bo'lganda bittaga o'rnatiladi, masalan, bir ip ikkinchisining ishlashni davom ettirishi uchun zarur bo'lgan ma'lumotlarni ishlab chiqaradi. Biroq, ko'p hollarda, operatsion tizim tomonidan tizim qo'ng'iroqlari shaklida taqdim etilgan sinxronizatsiya vositalari samaraliroq yoki hatto yagona mumkin bo'lganlardir. Shunday qilib, turli jarayonlarga tegishli iplar bir-birining ishiga hech qanday tarzda aralashishga qodir emas. Operatsion tizim vositachiligisiz ular bir-birini to'xtata olmaydi yoki voqea sodir bo'lganligi haqida bir-birini xabardor qila olmaydi. Sinxronizatsiya vositalari operatsion tizim tomonidan nafaqat amaliy jarayonlarni sinxronlashtirish uchun, balki uning ichki ehtiyojlari uchun ham qo'llaniladi.

Odatda, operatsion tizim ishlab chiquvchilari dastur va tizim dasturchilari ixtiyorida sinxronlash vositalarining keng doirasini taqdim etadilar. Ushbu vositalar ierarxiyani tashkil qilishi mumkin, agar murakkabroqlari oddiyroq vositalar asosida qurilgan bo'lsa, shuningdek, funktsional jihatdan ixtisoslashgan bo'lishi mumkin, masalan, bitta jarayonning iplarini sinxronlashtirish vositalari, ma'lumotlar almashinuvida turli jarayonlarning iplarini sinxronlashtirish vositalari va boshqalar. Ko'pincha turli xil tizim qo'ng'iroqlarining funktsional imkoniyatlari bir-biriga mos keladi, shuning uchun dasturchi o'zining shaxsiy imtiyozlariga qarab bitta muammoni hal qilish uchun bir nechta qo'ng'iroqlardan foydalanishi mumkin.


Sinxronizatsiya va poyga zarurati

Ko'p tarmoqli tizimda sinxronizatsiya muammolarini e'tiborsiz qoldirish muammoni noto'g'ri hal qilishga yoki hatto tizimning ishdan chiqishiga olib kelishi mumkin. Masalan, (4.16-rasm) ma'lum bir korxona mijozlari ma'lumotlar bazasini yuritish vazifasini ko'rib chiqaylik. Har bir mijozga ma'lumotlar bazasida alohida yozuv beriladi, unda boshqa maydonlar qatorida Buyurtma va To'lov maydonlari mavjud. Ma'lumotlar bazasini yurituvchi dastur bir nechta oqimlarga ega bo'lgan yagona jarayon sifatida ishlab chiqilgan, jumladan, mijozlardan olingan buyurtmalar to'g'risidagi ma'lumotlarni ma'lumotlar bazasiga kiritadigan A ipi va ma'lumotlar bazasida mijozlarning hisob-fakturalar uchun to'lovlari to'g'risidagi ma'lumotlarni qayd etuvchi B. Bu ikkala mavzu ham uchta bosqichni o'z ichiga olgan bir xil algoritmlardan foydalangan holda umumiy ma'lumotlar bazasi faylida birgalikda ishlaydi.

2. Buyurtma (A oqimi uchun) yoki To'lov (B oqimi uchun) maydoniga yangi qiymat kiriting.

3. O'zgartirilgan yozuvni ma'lumotlar bazasi fayliga qaytaring.

https://pandia.ru/text/78/239/images/image002_238.gif" width="505" height="374 src=">

Guruch. 4.17. Nisbiy oqim tezligining muammoni hal qilish natijasiga ta'siri

Tanqidiy qism

Mavzuni sinxronlashtirishda muhim tushuncha dasturning "tanqidiy bo'limi" tushunchasidir. Tanqidiy qism- bu dasturning bir qismi bo'lib, uning bajarilishi natijasi oldindan aytib bo'lmaydigan darajada o'zgarishi mumkin, agar dasturning ushbu qismiga tegishli o'zgaruvchilar ushbu qismning bajarilishi hali tugallanmagan bo'lsa, boshqa oqimlar tomonidan o'zgartirilsa. Kritik bo'lim har doim ma'lum bir narsaga nisbatan aniqlanadi muhim ma'lumotlar muvofiqlashtirilmagan tarzda o'zgartirilsa, kiruvchi ta'sirlar paydo bo'lishi mumkin. Oldingi misolda muhim ma'lumotlar ma'lumotlar bazasi fayl yozuvlari edi. Muhim ma'lumotlar bilan ishlaydigan barcha mavzular aniqlangan muhim bo'limga ega bo'lishi kerak. E'tibor bering, turli mavzularda tanqidiy bo'lim odatda turli xil buyruqlar ketma-ketligidan iborat.

Musobaqalarning muhim ma'lumotlarga ta'sirini bartaraf etish uchun istalgan vaqtda ushbu ma'lumotlar bilan bog'liq bo'lgan muhim bo'limda faqat bitta ip mavjudligini ta'minlash kerak. Bu mavzu faol yoki to'xtatilgan holatda ekanligi muhim emas. Ushbu texnika deyiladi o'zaro istisno. Operatsion tizim o'zaro istisnolarni amalga oshirishning turli usullaridan foydalanadi. Ba'zi usullar faqat bitta jarayonning iplari kritik bo'limga kirganda o'zaro istisno qilish uchun mos keladi, boshqalari esa turli jarayonlarning iplari uchun o'zaro istisno qilishni ta'minlashi mumkin.

O'zaro istisno qilishni ta'minlashning eng oddiy va ayni paytda eng samarasiz usuli - bu muhim qismda bo'lganida, ish zarrachalari har qanday uzilishlarni o'chirish uchun operatsion tizim uchun ruxsat berishdir. Biroq, bu usul deyarli qo'llanilmaydi, chunki tizimni boshqarish uchun foydalanuvchi ipiga ishonish xavfli - u protsessorni uzoq vaqt egallashi mumkin va agar muhim qismda ip yiqilsa, butun tizim buziladi, chunki uzilishlarga hech qachon yo'l qo'yilmaydi.

2. Sinxronizatsiya mexanizmlari.

O'zgaruvchilarni bloklash

Bitta jarayonning iplarini sinxronlashtirish uchun dasturchi global dan foydalanishi mumkin blokirovka qiluvchi o'zgaruvchilar. Dasturchi ushbu o'zgaruvchilar bilan ishlaydi, ularga jarayonning barcha oqimlari to'g'ridan-to'g'ri kirish imkoniyatiga ega, OT tizimi qo'ng'iroqlariga murojaat qilmasdan.

Bu butun tekshirish va o'rnatish jarayoni davomida uzilishlarni o'chirib qo'yadi.

Yuqorida tavsiflangan usulda o'zaro istisno qilishni amalga oshirish muhim kamchilikka ega: bitta ip muhim bo'limda bo'lgan vaqt davomida, protsessorga kirish imkoniga ega bo'lgan bir xil resursga muhtoj bo'lgan boshqa ip doimiy ravishda blokirovka o'zgaruvchisini so'raydi va protsessor vaqtini behuda sarflaydi. unga ajratilgan bo'lib, u boshqa mavzuni bajarish uchun ishlatilishi mumkin. Ushbu kamchilikni bartaraf etish uchun ko'plab operatsion tizimlar muhim bo'limlar bilan ishlash uchun maxsus tizim chaqiruvlarini taqdim etadi.

Shaklda. 4.19-rasmda bu funksiyalar Windows NT operatsion tizimida o'zaro istisno qilishni qanday amalga oshirishi ko'rsatilgan. Muhim ma'lumotlarni o'zgartirishni boshlashdan oldin, tarmoq EnterCriticalSection() tizim chaqiruvini chiqaradi. Ushbu qo'ng'iroq birinchi navbatda, oldingi holatda bo'lgani kabi, muhim resurs holatini aks ettiruvchi blokirovka o'zgaruvchisini tekshirishni amalga oshiradi. Agar tizim chaqiruvi resurs band ekanligini aniqlasa (F(D) = 0), oldingi holatdan farqli o'laroq, u tsiklik so'rov o'tkazmaydi, lekin ipni kutish holatiga qo'yadi (D) va eslatma qiladi bu ip tegishli resurs mavjud bo'lganda faollashtirilishi kerak. Hozirda ushbu resursdan foydalanayotgan ip, tanqidiy qismdan chiqqandan so'ng, LeaveCriticalSectionO tizim funktsiyasini bajarishi kerak, buning natijasida blokirovka o'zgaruvchisi resursning bo'sh holatiga mos keladigan qiymatni oladi (F(D) = 1), va operatsion tizim bu resurs iplarini kutayotganlarning navbatini ko'rib chiqadi va birinchi ipni navbatdan tayyor holatga o'tkazadi.

Qo'shimcha xarajatlar" href="/text/category/nakladnie_rashodi/" rel="bookmark">Muhim bo'limga kirish va chiqish funktsiyasini amalga oshirish uchun OS xarajatlari olingan tejashdan oshib ketishi mumkin.

Semaforlar

Bloklash o'zgaruvchilarning umumlashtirilishi deyiladi Dijkstra semaforlari. Ikkilik o'zgaruvchilar o'rniga, Dijkstra manfiy bo'lmagan butun qiymatlarni qabul qila oladigan o'zgaruvchilardan foydalanishni taklif qildi. Hisoblash jarayonlarini sinxronlashtirish uchun ishlatiladigan bunday o'zgaruvchilar semaforlar deb ataladi.

Semaforlar bilan ishlash uchun an'anaviy ravishda P va V bilan belgilangan ikkita ibtidoiy kiritiladi. S o'zgaruvchisi semaforni ifodalasin. Keyin V(S) va P(S) amallar quyidagicha aniqlanadi.

* V(S): S o'zgaruvchisi bitta harakat sifatida 1 ga oshiriladi. Namuna olish, qurish va saqlashni to'xtatib bo'lmaydi. Ushbu operatsiyani bajarish paytida S o'zgaruvchisiga boshqa oqimlar kirishi mumkin emas.

* P(S): Agar iloji bo'lsa, S ni 1 ga kamaytiradi. Agar 5=0 bo'lsa va manfiy bo'lmagan butun qiymatlar hududida qolgan holda S ni kamaytirishning iloji bo'lmasa, u holda P operatsiyani chaqiruvchi ip bu qisqartirish mumkin bo'lguncha kutadi. Muvaffaqiyatli tekshirish va kamaytirish ham bo'linmas operatsiya hisoblanadi.

V va P ibtidoiylarni bajarishda uzilishlarga yo'l qo'yilmaydi.

S semafori faqat 0 va 1 qiymatlarini olishi mumkin bo'lgan maxsus holatda, u blokirovka qiluvchi o'zgaruvchiga aylanadi, shuning uchun ko'pincha ikkilik semafor deb ataladi. P-faoliyat uni bajarayotgan ipni kutish holatiga o'tkazish potentsialiga ega, V faoliyat esa, ba'zi hollarda, P faoliyati bilan to'xtatilgan boshqa ipni uyg'otishi mumkin.

Multiprogrammalash rejimida ishlaydigan ikkita ipning o'zaro ta'sirining klassik misoli yordamida semaforlardan foydalanishni ko'rib chiqamiz, ulardan biri ma'lumotlarni bufer puliga yozadi, ikkinchisi esa bufer pulidan o'qiydi. Bufer hovuzi har birida bitta yozuv bo'lishi mumkin bo'lgan N ta buferdan iborat bo'lsin. Umuman olganda, yozuvchi ip va o'quvchi ipi har xil tezlikka ega bo'lishi va turli intensivlikdagi bufer hovuziga kirishi mumkin. Bir davrda yozish tezligi o'qish tezligidan oshib ketishi mumkin, boshqasida - aksincha. Birgalikda to'g'ri ishlash uchun yozuvchi ip barcha buferlar band bo'lganda pauza qilishi va kamida bitta bufer bo'shatilganda uyg'onishi kerak. Bundan farqli o'laroq, barcha buferlar bo'sh bo'lganda o'quvchi to'xtatib turishi va kamida bitta yozuv paydo bo'lganda uyg'onishi kerak.

Ikkita semaforni kiritamiz: e - bo'sh buferlar soni va f - to'ldirilgan buferlar soni va boshlang'ich holatda e = N, a f = 0. Keyin umumiy bufer puliga ega bo'lgan iplarning ishlashini quyidagicha tasvirlash mumkin. (4.20-rasm).

Yozuvchi ip birinchi navbatda P(e) operatsiyasini bajaradi, uning yordamida bufer hovuzida bo'sh buferlar mavjudligini tekshiradi. P operatsiyasining semantikasiga muvofiq, agar e semafori 0 ga teng bo'lsa (ya'ni, hozirda bo'sh buferlar mavjud emas), u holda yozuvchi ip kutish holatiga kiradi. Agar e ning qiymati musbat son bo'lsa, u holda bo'sh buferlar sonini kamaytiradi, keyingi bo'sh buferga ma'lumotlarni yozadi va keyin V(f) operatsiyasi bilan egallangan buferlar sonini oshiradi. O'quvchi ipi xuddi shunday ishlaydi, farqi shundaki, u to'liq buferlarni tekshirishdan boshlanadi va ma'lumotlarni o'qib bo'lgach, bo'sh buferlar sonini oshiradi.

DIV_ADBLOCK860">

Semafor ham blokirovka o'zgaruvchisi sifatida ishlatilishi mumkin. Yuqorida muhokama qilingan misolda umumiy xotira maydoni bilan ishlashda to'qnashuvlarni bartaraf etish uchun biz buferga yozish va undan o'qish muhim bo'limlar deb hisoblaymiz. Ikkilik semafor b yordamida o'zaro istisno qilishni ta'minlaymiz (4.21-rasm). Ikkala mavzu ham buferlarning mavjudligini tekshirgandan so'ng, muhim bo'limning mavjudligini tekshirishlari kerak.

https://pandia.ru/text/78/239/images/image007_110.jpg" width="495" height="639 src=">

Guruch. 4.22. Dasturni bajarish jarayonida blokirovkalarning paydo bo'lishi

ESLATMA

O'liklarni oddiy navbatlardan farqlash kerak, garchi ikkalasi ham resurslar taqsimlanganda paydo bo'ladi va tashqi ko'rinishi o'xshash: ip to'xtatiladi va resurs bo'shashini kutadi. Biroq, navbat odatiy hodisa bo'lib, so'rovlar tasodifiy kelib tushganda yuqori resurslardan foydalanishning o'ziga xos belgisidir. Resurs hozirda mavjud bo'lmaganda navbat paydo bo'ladi, lekin bir muncha vaqt o'tgach chiqariladi, bu ipni bajarishni davom ettirishga imkon beradi. Nomidan ko'rinib turibdiki, boshi berk ko'chaga tushib qolish - bu biroz hal qilib bo'lmaydigan holat. Tugallanish yuzaga kelishining zaruriy sharti shundaki, ip bir vaqtning o'zida bir nechta resurslarga muhtoj.

Ko'rib chiqilgan misollarda, o'lik ikkita ip tomonidan yaratilgan, ammo ko'proq iplar bir-birini to'sib qo'yishi mumkin. Shaklda. 2.23-rasmda Ri resurslarining bir nechta Tj iplari o'rtasida shunday taqsimlanishi ko'rsatilgan, bu esa o'liklarning paydo bo'lishiga olib keldi. O'qlar oqimning manba talablarini ko'rsatadi. Qattiq strelka mos keladigan resurs ipga ajratilganligini bildiradi va nuqtali strelka ipni kerakli manbaga bog'laydi, lekin uni boshqa ip egallaganligi sababli hali ajratish mumkin emas. Masalan, T1 ishi ishni bajarish uchun R1 va R2 resurslariga muhtoj, ulardan faqat bittasi ajratilgan - R1 va R2 resurs T2 ipida ushlab turiladi. Rasmda ko'rsatilgan to'rtta ipning hech biri o'z ishini davom ettira olmaydi, chunki ular buning uchun barcha zarur resurslarga ega emaslar.

Tugallanishlar tufayli iplarning boshlagan ishni yakunlay olmasligi hisoblash tizimining ishlashini pasaytiradi. Shu sababli, o'liklarning oldini olish muammosiga katta e'tibor qaratilmoqda. Tugallanish yuz bergan taqdirda, tizim operator operatoriga vaqtinchalik manbalar mavjud emasligi sababli blokirovkani tanib olish va uni oddiy blokdan ajrata oladigan vositani taqdim etishi kerak. Nihoyat, agar blokirovka tashxisi qo'yilgan bo'lsa, unda blokirovkalarni olib tashlash va oddiy hisoblash jarayonini tiklash uchun vositalar kerak bo'ladi.

Egasi" href="/text/category/vladeletc/" rel="bookmark">egasi, uni signalsiz holatga o'rnatadi va muhim bo'limga kiradi. Mavzu muhim ma'lumotlar bilan ishlashni tugatgandan so'ng, u "beradi. up” mutexni signalli holatga o‘rnatadi. Ayni damda mutex bo‘sh va hech qanday ipga tegishli emas. Agar biror ip uning chiqarilishini kutayotgan bo‘lsa, u holda bu mutexning keyingi egasi bo‘ladi. bir vaqtning o'zida mutex signalsiz holatga o'tadi.

Hodisa ob'ekti (bu holda "voqea" so'zi tor ma'noda, sinxronizatsiya ob'ektining ma'lum bir turini belgilash sifatida ishlatiladi) odatda ma'lumotlarga kirish uchun emas, balki ba'zi harakatlar tugaganligi haqida boshqa oqimlarni xabardor qilish uchun ishlatiladi. Misol uchun, ba'zi ilovalarda ish shunday tashkil qilinsinki, bitta ip fayldan ma'lumotlarni xotira buferiga o'qiydi va boshqa oqimlar bu ma'lumotlarni qayta ishlaydi, keyin birinchi ip ma'lumotlarning yangi qismini va boshqa oqimlarni o'qiydi. uni qayta ishlash va hokazo. Bajarish boshlanishida birinchi ip voqea ob'ektini signalsiz holatga o'rnatadi. Boshqa barcha oqimlar Wait(X) ga qo'ng'iroq qildi, bu erda X hodisa ko'rsatgichi bo'lib, to'xtatilgan holatda, bu voqea sodir bo'lishini kutmoqda. Bufer to'lgandan so'ng, birinchi tarmoq bu haqda Set(X) ga qo'ng'iroq qilib operatsion tizimga xabar beradi. Operatsion tizim kutilayotgan iplar navbatini skanerlaydi va ushbu hodisani kutayotgan har qanday mavzularni faollashtiradi.

Signallar

Signal Vazifaga voqeaga javob berish imkonini beradi, uning manbai operatsion tizim yoki boshqa vazifa bo'lishi mumkin. Signallarga vazifani to'xtatish va oldindan belgilangan harakatlarni bajarish kiradi. Signallar sinxron tarzda, ya'ni jarayonning o'zi ishi natijasida hosil bo'lishi mumkin yoki ular boshqa jarayon orqali jarayonga yuborilishi mumkin, ya'ni asinxron hosil bo'lishi mumkin. Sinxron signallar ko'pincha protsessorning uzilish tizimidan keladi va nolga bo'linish, adreslash xatosi, xotira himoyasi buzilishi va boshqalar kabi apparat tomonidan bloklangan jarayon harakatlarini ko'rsatadi.

Asinxron signalga misol terminaldan kelgan signaldir. Ko'pgina operatsion tizimlar jarayonni bajarishdan tezda olib tashlashni ta'minlaydi. Buning uchun foydalanuvchi ma'lum tugmalar birikmasini (Ctrl+C, Ctrl+Break) bosishi mumkin, buning natijasida OT signal hosil qiladi va uni faol jarayonga yuboradi. Signal jarayonning bajarilishi paytida istalgan vaqtda kelishi mumkin (ya'ni, u asinxrondir), bu jarayonni darhol tugatishni talab qiladi. Bunday holda, signalga javob jarayonning so'zsiz yakunlanishi hisoblanadi.

Tizimda signallar to'plami aniqlanishi mumkin. Signalni qabul qilgan jarayonning dastur kodi uni e'tiborsiz qoldirishi yoki unga standart harakat (masalan, chiqish) bilan javob berishi yoki dasturchi tomonidan aniqlangan muayyan harakatlarni bajarishi mumkin. Ikkinchi holda, dastur kodida maxsus tizim qo'ng'iroqlarini ta'minlash kerak, uning yordamida operatsion tizim ma'lum bir signalni qabul qilishga javoban qaysi protsedurani bajarish kerakligi haqida xabar beradi.

Signallar jarayonlar va foydalanuvchilar (terminallar) o'rtasidagi mantiqiy aloqani ta'minlaydi. Signal yuborish jarayon identifikatorini bilishni talab qilganligi sababli, signallar orqali o'zaro aloqa faqat bir-birining identifikatorlari haqida ma'lumot olishi mumkin bo'lgan bog'liq jarayonlar o'rtasida mumkin.

Har birining o'z operativ xotirasiga ega bo'lgan bir nechta protsessorlardan tashkil topgan taqsimlangan tizimlarda qulflash o'zgaruvchilari, semaforlar, signallar va shunga o'xshash umumiy xotiraga asoslangan boshqa funktsiyalar mos kelmaydi. Bunday tizimlarda sinxronizatsiya faqat xabar almashish orqali amalga oshirilishi mumkin.

Jarayon xotiraga yuklangan dasturning namunasidir. Ushbu misol bajarish uchun ko'rsatmalar ketma-ketligi bo'lgan iplarni yaratishi mumkin. Bu ishlayotgan jarayonlar emas, balki iplar ekanligini tushunish muhimdir.

Bundan tashqari, har qanday jarayonda kamida bitta ip mavjud. Bu ip ilovaning asosiy (asosiy) ipi deb ataladi.

Jismoniy protsessorlarga qaraganda deyarli har doim ko'proq iplar mavjud bo'lganligi sababli, iplar aslida bir vaqtning o'zida bajarilmaydi, balki o'z navbatida (protsessor vaqti iplar o'rtasida taqsimlanadi). Ammo ular o'rtasida almashinish shunchalik tez-tez sodir bo'ladiki, ular parallel ravishda ishlayotganga o'xshaydi.

Vaziyatga qarab, iplar uchta holatda bo'lishi mumkin. Birinchidan, ip protsessor vaqti ajratilganda bajarilishi mumkin, ya'ni. u faoliyat holatida bo'lishi mumkin. Ikkinchidan, u faol bo'lmagan va protsessor ajratilishini kutishi mumkin, ya'ni. tayyor holatda bo'lish. Va uchinchi, shuningdek, juda muhim davlat bor - blokirovka holati. Agar ip bloklangan bo'lsa, u hech qanday vaqt ajratilmaydi. Odatda, biron bir hodisa kutilayotganda blok qo'yiladi. Ushbu hodisa sodir bo'lganda, ip avtomatik ravishda bloklangan holatdan tayyor holatga o'tadi. Misol uchun, agar bitta ip hisob-kitoblarni amalga oshirsa, ikkinchisi esa natijalarni diskda saqlashni kutishi kerak. Ikkinchisi "while(!isCalcFinished) continue;" kabi sikldan foydalanishi mumkin, biroq amalda bu siklni bajarish jarayonida protsessor 100% band ekanligini tekshirish oson (bu faol kutish deb ataladi). Agar iloji bo'lsa, qulflash mexanizmi bebaho yordam beradigan bunday tsikllardan qochish kerak. Birinchi ip o'qish tugallanganligini ko'rsatuvchi hodisani ko'tarmaguncha ikkinchi ip o'zini bloklashi mumkin.

Windows operatsion tizimida iplarni sinxronlash

Windows preemptive multitaskingni amalga oshiradi - bu shuni anglatadiki, tizim istalgan vaqtda bir ipning bajarilishini to'xtatishi va boshqaruvni boshqasiga o'tkazishi mumkin. Ilgari, Windows 3.1 da kooperativ multitasking deb nomlangan tashkilot usuli qo'llanilgan: tizim ipning o'zi boshqaruvni unga o'tkazguncha kutib turdi va shuning uchun agar bitta dastur qotib qolsa, kompyuterni qayta ishga tushirish kerak edi.

Xuddi shu jarayonga tegishli bo'lgan barcha oqimlar ba'zi umumiy resurslarni baham ko'radi - masalan, RAM manzil maydoni yoki ochiq fayllar. Ushbu manbalar butun jarayonga, shuning uchun uning har bir qismiga tegishli. Shuning uchun, har bir mavzu ushbu resurslar bilan hech qanday cheklovlarsiz ishlashi mumkin. Lekin... Agar biror ip hali biror umumiy resurs bilan ishlashni tugatmagan bo‘lsa va tizim xuddi shu resursdan foydalangan holda boshqa ipga o‘tsa, u holda bu iplar ishining natijasi mo‘ljallanganidan keskin farq qilishi mumkin. Bunday qarama-qarshiliklar turli jarayonlarga tegishli iplar o'rtasida ham paydo bo'lishi mumkin. Ikki yoki undan ortiq mavzular har qanday umumiy manbani baham ko'rsa, bu muammo yuzaga keladi.

Misol. Sinxronlashtirilmagan mavzular: Agar siz ko'rsatish oqimini vaqtincha to'xtatib qo'ysangiz (to'xtatib qo'ysangiz), fon massivini joylashtirish oqimi ishlashda davom etadi.

#o'z ichiga oladi #o'z ichiga oladi int a; HANDLE hThr; imzosiz uzun uThrID; void Thread(void* pParams) ( int i, num = 0; while (1) ( for (i=0; i)<5; i++) a[i] = num; num++; } } int main(void) { hThr=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,NULL,0,&uThrID); while(1) printf("%d %d %d %d %d\n", a, a, a, a, a); return 0; }

Shuning uchun ish zarrachalariga o'z ishlarini umumiy resurslar bilan muvofiqlashtirishga imkon beradigan mexanizm kerak. Bu mexanizm ipni sinxronlash mexanizmi deb ataladi.

Bu mexanizm operatsion tizim ob'ektlari to'plami bo'lib, ular dasturiy jihatdan yaratilgan va boshqariladigan, tizimdagi barcha oqimlar uchun umumiy bo'lgan (ba'zilari bir xil jarayonga tegishli bo'lgan iplar tomonidan taqsimlanadi) va resurslarga kirishni muvofiqlashtirish uchun ishlatiladi. Resurslar ikki yoki undan ortiq oqimlar bilan bo'lishish mumkin bo'lgan har qanday narsa bo'lishi mumkin - disk fayli, port, ma'lumotlar bazasiga kirish, GDI ob'ekti va hatto global dastur o'zgaruvchisi (bir xil jarayonga tegishli iplar orqali kirish mumkin).

Bir nechta sinxronizatsiya ob'ektlari mavjud bo'lib, ulardan eng muhimlari mutex, kritik bo'lim, hodisa va semafordir. Ushbu ob'ektlarning har biri o'zining sinxronlash usulini amalga oshiradi. Shuningdek, jarayonlar va oqimlarning o'zlari sinxronizatsiya ob'ektlari sifatida ishlatilishi mumkin (bir ip boshqa ip yoki jarayon tugashini kutayotganda); shuningdek, fayllar, aloqa qurilmalari, konsol kiritish va o'zgartirish bildirishnomalari.

Har qanday sinxronizatsiya ob'ekti signal deb ataladigan holatda bo'lishi mumkin. Har bir turdagi ob'ekt uchun bu holat har xil ma'noga ega. Mavzular ob'ektning joriy holatini tekshirishi va/yoki bu holatning o'zgarishini kutishi va shu bilan ularning harakatlarini muvofiqlashtirishi mumkin. Bu ish zarrachalari sinxronizatsiya ob'ektlari bilan ishlaganda (ularni yaratadi, holatini o'zgartiradi), tizim ushbu amalni tugatmaguncha uning bajarilishini to'xtatmasligini ta'minlaydi. Shunday qilib, sinxronizatsiya ob'ektlari bilan barcha yakuniy operatsiyalar atomik (bo'linmas.

Sinxronizatsiya ob'ektlari bilan ishlash

U yoki bu sinxronizatsiya obyektini yaratish uchun Create... tipidagi maxsus WinAPI funksiyasi chaqiriladi (masalan, CreateMutex). Ushbu qo'ng'iroq ushbu jarayonga tegishli barcha oqimlar tomonidan ishlatilishi mumkin bo'lgan ob'ektga (HANDLE) dastakni qaytaradi. Sinxronizatsiya ob'ektiga boshqa jarayondan kirish mumkin - bu ob'ektga tutqichni meros qilib olish orqali yoki, yaxshisi, ob'ektni ochish funksiyasiga qo'ng'iroq qilish (Ochish...). Ushbu qo'ng'iroqdan so'ng, jarayon keyinchalik ob'ekt bilan ishlash uchun ishlatilishi mumkin bo'lgan tutqichni oladi. Ob'ekt, agar u bitta jarayonda foydalanish uchun mo'ljallanmagan bo'lsa, unga nom berilishi kerak. Barcha ob'ektlarning nomlari har xil bo'lishi kerak (ular har xil turdagi bo'lsa ham). Masalan, siz bir xil nomdagi hodisa va semafor yarata olmaysiz.

Ob'ektning mavjud deskriptoridan foydalanib, uning hozirgi holatini aniqlashingiz mumkin. Bu deb atalmish yordamida amalga oshiriladi. kutilayotgan funktsiyalar. Eng ko'p ishlatiladigan funksiya WaitForSingleObject. Bu funktsiya ikkita parametrni oladi, ulardan birinchisi ob'ekt dastagi, ikkinchisi ms dagi vaqt tugashi. Agar ob'ekt signal holatida bo'lsa, funktsiya WAIT_OBJECT_0, agar vaqt tugagan bo'lsa WAIT_TIMEOUT va agar mutex ob'ekti o'ziga tegishli bo'lgan oqim chiqishidan oldin bo'shatilmagan bo'lsa WAIT_ABANDONED qaytaradi. Vaqt tugashi nolga teng bo'lsa, funktsiya darhol natijani qaytaradi, aks holda u belgilangan vaqtni kutadi. Agar bu vaqt tugashidan oldin ob'ekt holati signalga aylansa, funksiya WAIT_OBJECT_0 qaytaradi, aks holda funksiya WAIT_TIMEOUTni qaytaradi. Agar INFINITE ramziy doimiysi vaqt sifatida belgilangan bo'lsa, funksiya ob'ekt holati signalga aylanguncha cheksiz kutadi.

Juda muhim haqiqat shundaki, kutish funktsiyasini chaqirish joriy ipni bloklaydi, ya'ni. Tarmoq bo'sh holatda bo'lsa-da, unga protsessor vaqti ajratilmaydi.

Muhim bo'limlar

Muhim bo'lim ob'ekti dasturchiga kodning umumiy manbaga kirishi mumkin bo'lgan qismini ajratishga yordam beradi va manbadan bir vaqtda foydalanishni oldini oladi. Resursdan foydalanishdan oldin ip muhim bo'limga kiradi (EnterCriticalSection funktsiyasini chaqiradi). Agar bir xil kritik bo'limga boshqa har qanday mavzu kirishga harakat qilsa, uning bajarilishi LeaveCriticalSection ga qo'ng'iroq qilib, birinchi ip bo'limdan chiqmaguncha to'xtatiladi. Faqat bitta jarayonning iplari uchun ishlatiladi. Kritik bo'limga kirish tartibi aniqlanmagan.

TryEnterCriticalSection funksiyasi ham mavjud bo'lib, u hozirda muhim bo'lim bandligini tekshiradi. Uning yordami bilan, manbaga kirishni kutayotganda, ipni bloklab bo'lmaydi, lekin ba'zi foydali harakatlarni bajaring.

Misol. Muhim bo'limlar yordamida iplarni sinxronlash.

#o'z ichiga oladi #o'z ichiga oladi CRITICAL_SECTION cs; int a; HANDLE hThr; imzosiz uzun uThrID; void Thread(void* pParams) ( int i, num = 0; while (1) ( EnterCriticalSection(&cs); for (i=0; i)<5; i++) a[i] = num; num++; LeaveCriticalSection(&cs); } } int main(void) { InitializeCriticalSection(&cs); hThr=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,NULL,0,&uThrID); while(1) { EnterCriticalSection(&cs); printf("%d %d %d %d %d\n", a, a, a, a, a); LeaveCriticalSection(&cs); } return 0; }

O'zaro istisnolar

O'zaro istisno ob'ektlari (mutexlar, mutex - MUTual Exclusion dan) umumiy manbaga kirishni o'zaro istisno qilishni muvofiqlashtirish imkonini beradi. Ob'ektning signal holati (ya'ni, "o'rnatilgan" holat) ob'ekt hech qanday ipga tegishli bo'lmagan va "qo'lga olinishi" mumkin bo'lgan vaqtga to'g'ri keladi. Aksincha, "qayta o'rnatish" (signal bo'lmagan) holati ba'zi bir ip allaqachon ushbu ob'ektga ega bo'lgan paytga to'g'ri keladi. Ob'ektga kirish huquqi ob'ektga ega bo'lgan ip uni ozod qilganda beriladi.

Ikki (yoki undan ko'p) iplar CreateMutex funksiyasini chaqirish orqali bir xil nomli mutex yaratishi mumkin. Birinchi ip aslida mutexni yaratadi va keyingilari allaqachon mavjud ob'ektga ishlov beradi. Bu bir nechta iplarga bir xil mutexga ishlov berish imkonini beradi, bu esa dasturchini mutexni kim yaratayotgani haqida tashvishlanishdan ozod qiladi. Agar ushbu yondashuv qo'llanilsa, bInitialOwner bayrog'ini FALSE ga o'rnatish tavsiya etiladi, aks holda mutexning haqiqiy yaratuvchisini aniqlashda biroz qiyinchiliklar paydo bo'ladi.

Bir nechta iplar bir xil mutex uchun tutqichni olishi mumkin, bu esa jarayonlararo aloqani ta'minlaydi. Ushbu yondashuv uchun quyidagi mexanizmlardan foydalanish mumkin:

  • CreateProcess funksiyasi yordamida yaratilgan bola jarayoni, agar CreateMutex funksiyasi bilan mutex yaratishda lpMutexAttributes parametri belgilangan bo'lsa, mutex tutqichini meros qilib olishi mumkin.
  • DuplicateHandle funksiyasidan foydalanib, ip mavjud mutexning dublikatini olishi mumkin.
  • OpenMutex yoki CreateMutex funksiyalarini chaqirishda ip mavjud mutex nomini belgilashi mumkin.

O'zaro istisnoni joriy oqimga tegishli deb e'lon qilish uchun siz kutish funktsiyalaridan birini chaqirishingiz kerak. Ob'ektga ega bo'lgan ip uni xohlagancha ko'p marta olishi mumkin (bu o'z-o'zini blokirovka qilishga olib kelmaydi), lekin ReleaseMutex funktsiyasidan foydalangan holda uni bir xil miqdordagi chiqarishi kerak.

Bitta jarayonning iplarini sinxronlashtirish uchun muhim bo'limlardan foydalanish samaraliroq bo'ladi.

Misol. Mutekslar yordamida iplarni sinxronlash.

#o'z ichiga oladi #o'z ichiga oladi HANDLE hMutex; int a; HANDLE hThr; imzosiz uzun uThrID; void Thread(void* pParams) ( int i, num = 0; while (1) ( WaitForSingleObject(hMutex, INFINITE); for (i=0; i)<5; i++) a[i] = num; num++; ReleaseMutex(hMutex); } } int main(void) { hMutex=CreateMutex(NULL, FALSE, NULL); hThr=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,NULL,0,&uThrID); while(1) { WaitForSingleObject(hMutex, INFINITE); printf("%d %d %d %d %d\n", a, a, a, a, a); ReleaseMutex(hMutex); } return 0; }

Voqealar

Voqea ob'ektlari kutilayotgan mavzularni voqea sodir bo'lganligi haqida xabardor qilish uchun ishlatiladi. Ikki turdagi hodisalar mavjud - qo'lda va avtomatik qayta o'rnatish bilan. Qo'lda tiklash ResetEvent funktsiyasi tomonidan amalga oshiriladi. Qo'lda tiklash hodisalari bir vaqtning o'zida bir nechta mavzularni xabardor qilish uchun ishlatiladi. Avtomatik tiklash hodisasidan foydalanilganda, faqat bitta kutayotgan oqim bildirishnoma oladi va ishlashni davom ettiradi; qolganlari kutishda davom etadi.

CreateEvent funktsiyasi hodisa ob'ektini yaratadi, SetEvent - hodisani signal holatiga o'rnatadi, ResetEvent - hodisani qayta tiklaydi. PulseEvent funktsiyasi hodisani o'rnatadi va bu hodisani kutayotgan iplar davom etgandan so'ng (ularning barchasi qo'lda qayta o'rnatilganda va faqat bittasi avtomatik qayta o'rnatilganda) uni qayta tiklaydi. Agar kutish mavzulari bo'lmasa, PulseEvent shunchaki hodisani qayta tiklaydi.

Misol. Voqealar yordamida mavzularni sinxronlash.

#o'z ichiga oladi #o'z ichiga oladi HEVENT1, HEvent2; int a; HANDLE hThr; imzosiz uzoq uThrID; void Thread(void* pParams) ( int i, num = 0; while (1) ( WaitForSingleObject(hEvent2, INFINITE); uchun (i=0; i)<5; i++) a[i] = num; num++; SetEvent(hEvent1); } } int main(void) { hEvent1=CreateEvent(NULL, FALSE, TRUE, NULL); hEvent2=CreateEvent(NULL, FALSE, FALSE, NULL); hThr=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,NULL,0,&uThrID); while(1) { WaitForSingleObject(hEvent1, INFINITE); printf("%d %d %d %d %d\n", a, a, a, a, a); SetEvent(hEvent2); } return 0; }

Semaforlar

Semafor ob'ekti aslida hisoblagichga ega mutex ob'ektidir. Ushbu ob'ekt o'zini ma'lum miqdordagi iplar tomonidan "qo'lga olish" imkonini beradi. Shundan so'ng, semaforni ilgari "qo'lga olgan" iplardan biri uni chiqarmaguncha, "qo'lga olish" imkonsiz bo'ladi. Semaforlar resurs bilan bir vaqtda ishlaydigan iplar sonini cheklash uchun ishlatiladi. Initsializatsiya paytida maksimal iplar soni ob'ektga o'tkaziladi, har bir "qo'lga olish" dan keyin semafor hisoblagichi kamayadi. Signal holati noldan katta hisoblagich qiymatiga mos keladi. Hisoblagich nolga teng bo'lsa, sema o'rnatilmagan (qayta o'rnatilmagan) hisoblanadi.

CreateSemaphore funksiyasi uning maksimal mumkin bo'lgan boshlang'ich qiymatini ko'rsatuvchi semafor ob'ektini yaratadi, OpenSemaphore - mavjud semaforning deskriptorini qaytaradi, semafor kutish funktsiyalari yordamida olinadi va semafor qiymati bittaga kamayadi, ReleaseSemaphore - semafor semafor bilan birga chiqariladi. parametr raqamida ko'rsatilgan qiymatga ko'tarilgan qiymat.

Misol. Semaforlar yordamida iplarni sinxronlash.

#o'z ichiga oladi #o'z ichiga oladi HANDLE hSem; int a; HANDLE hThr; imzosiz uzun uThrID; void Thread(void* pParams) ( int i, num = 0; while (1) ( WaitForSingleObject(hSem, INFINITE); (i=0; i) uchun<5; i++) a[i] = num; num++; ReleaseSemaphore(hSem, 1, NULL); } } int main(void) { hSem=CreateSemaphore(NULL, 1, 1, "MySemaphore1"); hThr=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,NULL,0,&uThrID); while(1) { WaitForSingleObject(hSem, INFINITE); printf("%d %d %d %d %d\n", a, a, a, a, a); ReleaseSemaphore(hSem, 1, NULL); } return 0; }

O'zgaruvchilarga himoyalangan kirish

Sinxronizatsiya haqida qayg'urmasdan, barcha mavzulardagi global o'zgaruvchilar bilan ishlashga imkon beruvchi bir qator funktsiyalar mavjud, chunki bu funktsiyalar buni o'zlari nazorat qiladi - ularning bajarilishi atomikdir. Bu funksiyalar InterlockedIncrement, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd va InterlockedCompareExchange. Masalan, InterlockedIncrement funktsiyasi 32 bitli o'zgaruvchining qiymatini atomik ravishda bittaga oshiradi, bu esa turli hisoblagichlar uchun foydalanish uchun qulaydir.

Barcha WIN32 API funktsiyalarining maqsadi, ishlatilishi va sintaksisi haqida to'liq ma'lumot olish uchun siz Borland Delphi yoki CBuilder dasturlash muhitiga kiritilgan MS SDK yordam tizimidan, shuningdek Visual C dasturlash tizimining bir qismi sifatida taqdim etilgan MSDN dan foydalanishingiz kerak.

Mavzular bir nechta holatlardan birida bo'lishi mumkin:

    Tayyor(tayyor) - bajarilishini kutayotgan iplar havzasida joylashgan;

    Yugurish(bajarish) - protsessorda ishlash;

    Kutilmoqda(kutish), bo'sh yoki to'xtatilgan deb ham ataladi, to'xtatilgan - kutish holatida bo'lib, u ishlay boshlashi (Ishlayotgan holat) yoki holatga kirishi bilan tugaydi. Tayyor;

    Tugatilgan (tugatish) - barcha ip buyruqlarini bajarish tugallandi. Keyinchalik uni o'chirib tashlash mumkin. Agar oqim o'chirilmasa, tizim keyinchalik foydalanish uchun uni asl holatiga qaytarishi mumkin.

Mavzuni sinxronlashtirish

Ishlayotgan iplar ko'pincha qandaydir tarzda muloqot qilishlari kerak. Misol uchun, agar bir nechta ish zarralari ba'zi global ma'lumotlarga kirishga harakat qilsa, u holda har bir mavzu ma'lumotlarni boshqa oqim tomonidan o'zgartirilishidan himoya qilishi kerak. Ba'zan bitta ip boshqa ish zarrachalari topshiriqni qachon bajarishini bilishi kerak. Bunday o'zaro ta'sir bir xil va turli jarayonlarning iplari o'rtasida majburiydir.

Mavzuni sinxronlashtirish ( ip sinxronizatsiya) iplarning oʻzaro taʼsiri va oʻzaro bogʻlanishi jarayoniga ishora qiluvchi umumiy atama. Iltimos, esda tutingki, iplarni sinxronlash operatsion tizimning o'zi vositachi sifatida harakat qilishini talab qiladi. Uning ishtirokisiz iplar bir-biri bilan o'zaro ta'sir qila olmaydi.

Win32-da iplarni sinxronlashtirishning bir necha usullari mavjud. Muayyan vaziyatda bitta usul boshqasidan ko'ra afzalroq bo'ladi. Keling, ushbu usullarni tezda ko'rib chiqaylik.

Muhim bo'limlar

Mavzularni sinxronlashtirish usullaridan biri muhim bo'limlardan foydalanishdir. Bu Windows yadrosini talab qilmaydigan yagona ip sinxronlash usuli. (Muhim bo'lim yadro ob'ekti emas.) Biroq, bu usul faqat bitta jarayonning iplarini sinxronlashtirish uchun ishlatilishi mumkin.

Kritik bo'lim - bu bir vaqtning o'zida faqat bitta ip tomonidan bajarilishi mumkin bo'lgan kod bo'limi. Agar massivni ishga tushirish uchun foydalanilgan kod muhim bo'limga joylashtirilgan bo'lsa, birinchi ip uni bajarishni tugatmaguncha, boshqa mavzular kodning ushbu bo'limiga kira olmaydi.

Muhim qismdan foydalanishdan oldin uni Win32 API protsedurasi InitializeCriticalSection() yordamida ishga tushirishingiz kerak, bu (Delphida) quyidagicha aniqlanadi:

procedure InitializeCriticalSection(var IpCriticalSection: TRTLCriticalSection); stdcall;

IpCriticalSection parametri mos yozuvlar orqali uzatiladigan TRTLCriticalSection turidagi yozuvdir. TRTLCriticalSection yozuvining aniq ta'rifi unchalik muhim emas, chunki siz uning mazmuniga hech qachon qarashingiz shart emas. Siz qilishingiz kerak bo'lgan yagona narsa IpCtitical Section parametriga ishga tushirilmagan yozuvni o'tkazish va bu yozuv darhol protsedura bilan to'ldiriladi.

Dasturdagi yozuvni to'ldirgandan so'ng, uning matnining bir qismini EnterCriticalSection() va LeaveCriticalSection() funksiyalariga qo'ng'iroqlar orasiga qo'yib, muhim bo'lim yaratishingiz mumkin. Ushbu protseduralar quyidagicha aniqlanadi:

protsedura EnterCriticalSection(var IpCriticalSection: TRTLCriticalSection); stdcall;

procedure LeaveCriticalSection(var IpCriticalSection: TRTLCriticalSection); stdcall;

Ushbu protseduralarga uzatiladigan IpCriticalSection parametri InitializeCriticalSection() protsedurasi tomonidan yaratilgan yozuvdan boshqa narsa emas.

Funktsiya EnterCriticalSection boshqa bir ish zarrachasi o'z dasturining berilgan muhim bo'lim ob'ekti bilan bog'langan muhim qismini allaqachon bajarayotganligini tekshiradi. Agar yo'q bo'lsa, ip o'zining muhim kodini bajarish uchun ruxsat oladi, to'g'rirog'i, buni amalga oshirishga to'sqinlik qilmaydi. Agar shunday bo'lsa, u holda so'rovni yuboruvchi ip kutish holatiga o'tkaziladi va so'rov bo'yicha yozuv olinadi. Yozuvlar yaratilishi kerakligi sababli, muhim bo'lim ob'ekti ma'lumotlar strukturasi hisoblanadi.

Funktsiya qachon Kritik bo'limni tark eting ma'lum bir muhim bo'lim ob'ekti bilan bog'langan kodning muhim qismini bajarish uchun ruxsatga ega bo'lgan ish zarrachalari tomonidan chaqirilganda, tizim navbatda ushbu ob'ektning chiqarilishini kutayotgan boshqa ish zarrachalari mavjudligini tekshirishi mumkin. Shundan so'ng tizim kutayotgan ipni kutish holatidan olib tashlashi mumkin va u o'z ishini davom ettiradi (unga ajratilgan vaqt oralig'ida).

TRTLCriticalSection yozuvi bilan ishlashni tugatgandan so'ng, DeleteCriticalSection() protsedurasini chaqirish orqali uni bo'shatish kerak, bu quyidagicha aniqlanadi:

protsedurasini DeleteCriticalSection(var IpCriticalSection: TRTLCriticalSection); stdcall;

Ba'zan bir nechta iplar yoki jarayonlar bilan ishlashda zarurat tug'iladi bajarilishini sinxronlashtirish ulardan ikkitasi yoki undan ko'pi. Buning sababi, ko'pincha ikki yoki undan ortiq mavzular umumiy manbaga kirishni talab qilishi mumkin haqiqatan ham bir vaqtning o'zida bir nechta mavzularni taqdim etish mumkin emas. Umumiy resurs - bu bir vaqtning o'zida bir nechta ishlaydigan vazifalar orqali kirish mumkin bo'lgan resurs.

Sinxronizatsiya jarayonini ta'minlaydigan mexanizm deyiladi kirishni cheklash. Unga bo'lgan ehtiyoj, shuningdek, bitta ip boshqa ip tomonidan yaratilgan hodisani kutayotgan hollarda paydo bo'ladi. Tabiiyki, voqea sodir bo'lishidan oldin birinchi ipni to'xtatib qo'yishning qandaydir usuli bo'lishi kerak. Shundan so'ng, ip o'z bajarilishini davom ettirishi kerak.

Vazifa bo'lishi mumkin bo'lgan ikkita umumiy holat mavjud. Birinchidan, vazifa mumkin amalga oshirilsin(yoki protsessor resurslariga kirishi bilanoq bajarishga tayyor bo'ling). Ikkinchidan, vazifa bo'lishi mumkin bloklangan. Bunday holda, uning bajarilishi kerakli resurs bo'shatilguncha yoki ma'lum bir hodisa ro'y berguncha to'xtatiladi.

Windows-da ma'lum bir tarzda umumiy resurslarga kirishni cheklash imkonini beruvchi maxsus xizmatlar mavjud, chunki operatsion tizimning yordamisiz alohida jarayon yoki oqim resursga yagona kirish imkoniyatini o'zi aniqlay olmaydi. Windows operatsion tizimida bitta uzluksiz operatsiya davomida tekshiradigan va iloji bo'lsa, resurslarga kirish bayrog'ini o'rnatadigan protsedura mavjud. Operatsion tizim ishlab chiquvchilari tilida bu operatsiya deyiladi tekshirish va o'rnatish ishlashi. Sinxronizatsiyani ta'minlash va resurslarga kirishni boshqarish uchun ishlatiladigan bayroqlar deyiladi semaforlar(semafor). Win32 API semaforlar va boshqa sinxronizatsiya ob'ektlarini qo'llab-quvvatlaydi. MFC kutubxonasi ushbu ob'ektlarni qo'llab-quvvatlashni ham o'z ichiga oladi.

Sinxronizatsiya ob'ektlari va mfc sinflari

Win32 interfeysi to'rt turdagi sinxronizatsiya ob'ektlarini qo'llab-quvvatlaydi - ularning barchasi qandaydir tarzda semafor tushunchasiga asoslangan.

Birinchi turdagi ob'ekt semaforning o'zi yoki klassik (standart) semafor. Bu cheklangan miqdordagi jarayonlar va oqimlarga bitta resursga kirish imkonini beradi. Bunday holda, resursga kirish butunlay cheklangan (bitta va faqat bitta oqim yoki jarayon ma'lum vaqt oralig'ida resursga kirishi mumkin) yoki faqat oz miqdordagi iplar va jarayonlar bir vaqtning o'zida kirishni oladi. Semaforlar hisoblagich yordamida amalga oshiriladi, uning qiymati semafor vazifaga ajratilganda kamayadi va vazifa semaforni chiqarganda ortadi.

Sinxronizatsiya ob'ektlarining ikkinchi turi eksklyuziv (mutex) semafor. U resursga kirishni to'liq cheklash uchun mo'ljallangan, shuning uchun har qanday vaqtda faqat bitta jarayon yoki oqim manbaga kirishi mumkin. Aslida, bu semaforning maxsus turi.

Sinxronizatsiya ob'ektlarining uchinchi turi voqea, yoki hodisa ob'ekti. U resursdan foydalanish mumkinligini boshqa jarayon yoki oqim e'lon qilmaguncha resursga kirishni bloklash uchun ishlatiladi. Shunday qilib, bu ob'ekt talab qilinadigan hodisaning tugashi haqida signal beradi.

To'rtinchi turdagi sinxronizatsiya ob'ektidan foydalanib, dastur kodining ma'lum bo'limlarini bir vaqtning o'zida bir nechta iplar tomonidan bajarilishini taqiqlashingiz mumkin. Buning uchun ushbu hududlar deb e'lon qilinishi kerak tanqidiy bo'lim. Ushbu bo'limga bitta ip kirsa, birinchi ip bo'limdan chiqmaguncha, boshqa iplar ham xuddi shunday qilishlari taqiqlanadi.

Kritik bo'limlar, sinxronizatsiya ob'ektlarining boshqa turlaridan farqli o'laroq, faqat bir xil jarayon doirasidagi iplarni sinxronlashtirish uchun ishlatiladi. Jarayon ichidagi oqimlarni sinxronlashtirish yoki jarayonlarni sinxronlashtirish uchun boshqa turdagi ob'ektlardan foydalanish mumkin.

MFC-da Win32 interfeysi tomonidan taqdim etilgan sinxronizatsiya mexanizmi CSyncObject sinfidan olingan quyidagi sinflar tomonidan qo'llab-quvvatlanadi:

    CCriticalSection- tanqidiy qismni amalga oshiradi.

    CEvent- hodisa obyektini amalga oshiradi

    CMutex- eksklyuziv semani amalga oshiradi.

    CSemafora- klassik semani amalga oshiradi.

Ushbu sinflarga qo'shimcha ravishda, MFC ikkita yordamchi sinxronizatsiya sinfini ham belgilaydi: CSingleLock Va CMultiLock. Ular sinxronizatsiya ob'ektiga kirishni nazorat qiladi va bunday ob'ektlarni taqdim etish va chiqarish uchun ishlatiladigan usullarni o'z ichiga oladi. Sinf CSingleLock yagona sinxronlash obyektiga va sinfga kirishni nazorat qiladi CMultiLock- bir nechta ob'ektlarga. Keyinchalik biz faqat sinfni ko'rib chiqamiz CSingleLock.

Har qanday sinxronizatsiya ob'ekti yaratilgandan so'ng, unga kirishni sinf yordamida boshqarish mumkin CSingleLock. Buning uchun avvalo turdagi ob'ektni yaratish kerak CSingleLock konstruktor yordamida:

CSingleLock(CSyncObject* pObject, BOOL bInitialLock = FALSE);

Birinchi parametr ko'rsatgichni sinxronizatsiya ob'ektiga, masalan, semaforga o'tkazadi. Ikkinchi parametrning qiymati konstruktor ushbu ob'ektga kirishga harakat qilishi kerakligini aniqlaydi. Agar bu parametr nolga teng bo'lmasa, u holda kirish olinadi, aks holda kirishga urinishlar amalga oshirilmaydi. Agar kirish huquqi berilsa, u holda sinf ob'ektini yaratgan ip CSingleLock, mos keladigan sinxronizatsiya ob'ekti usul bilan chiqarilguncha to'xtatiladi Qulfni ochish sinf CSingleLock.

CSingleLock tipidagi ob'ekt yaratilganda, pObject tomonidan ko'rsatilgan ob'ektga kirish ikkita funktsiya yordamida boshqarilishi mumkin: Qulflash Va Qulfni ochish sinf CSingleLock.

Usul Qulflash ob'ektga sinxronizatsiya ob'ektiga kirish uchun mo'ljallangan. Uni chaqirgan ip usul tugagunga qadar, ya'ni resursga kirish olinmaguncha to'xtatiladi. Parametrning qiymati funksiya kerakli ob'ektga kirish uchun qancha vaqt kutishini aniqlaydi. Har safar usul muvaffaqiyatli yakunlanganda, sinxronizatsiya ob'ekti bilan bog'langan hisoblagichning qiymati bittaga kamayadi.

Usul Qulfni ochish Sinxronizatsiya ob'ektini chiqaradi, bu boshqa oqimlarga resursdan foydalanishga ruxsat beradi. Usulning birinchi versiyasida ushbu ob'ekt bilan bog'langan hisoblagichning qiymati bittaga oshiriladi. Ikkinchi variantda birinchi parametr bu qiymatni qanchalik oshirish kerakligini aniqlaydi. Ikkinchi parametr oldingi hisoblagich qiymati yoziladigan o'zgaruvchiga ishora qiladi.

Sinf bilan ishlashda CSingleLock Resursga kirishni nazorat qilishning umumiy tartibi:

    resursga kirishni boshqarish uchun foydalaniladigan CSyncObj tipidagi ob'ektni yaratish (masalan, semafor);

    yaratilgan sinxronizatsiya ob'ektidan foydalanib, CSingleLock tipidagi ob'ektni yarating;

    resursga kirish uchun Lock usulini chaqiring;

    manbaga kirish;

    Resursni chiqarish uchun Unlock usulini chaqiring.

Quyida semaforlar va hodisa ob'ektlarini qanday yaratish va ulardan foydalanish tasvirlangan. Ushbu tushunchalarni tushunganingizdan so'ng, siz sinxronizatsiya ob'ektlarining boshqa ikkita turini osongina o'rganishingiz va ulardan foydalanishingiz mumkin: muhim bo'limlar va mutekslar.

Salom! Bugun biz ko'p tarmoqli dasturlashning xususiyatlarini ko'rib chiqishni davom ettiramiz va iplarni sinxronlashtirish haqida gaplashamiz.

"Sinxronizatsiya" nima? Dasturlash doirasidan tashqarida, bu ikkita qurilma yoki dasturning birgalikda ishlashiga imkon beruvchi qandaydir sozlashni anglatadi. Masalan, smartfon va kompyuter Google hisob qaydnomasi bilan, veb-saytdagi shaxsiy hisob esa ijtimoiy tarmoqlardagi akkauntlardan foydalanib tizimga kirish uchun sinxronlashtirilishi mumkin. Mavzuni sinxronlashtirish xuddi shunday ma'noga ega: bu iplarning bir-biri bilan o'zaro ta'sirini o'rnatish. Oldingi ma'ruzalarda bizning iplarimiz bir-biridan alohida yashagan va ishlagan. Biri nimanidir hisoblardi, ikkinchisi uxlab yotardi, uchinchisi konsolda nimanidir ko'rsatardi, lekin ular bir-birlari bilan aloqa qilmadilar. Haqiqiy dasturlarda bunday holatlar kam uchraydi. Bir nechta iplar, masalan, bir xil ma'lumotlar to'plami bilan faol ishlashi va undagi biror narsani o'zgartirishi mumkin. Bu muammolarni keltirib chiqaradi. Tasavvur qiling-a, bir nechta mavzular bir xil joyga matn yozmoqda - masalan, matn fayli yoki konsol. Ushbu fayl yoki konsol bu holda umumiy manbaga aylanadi. Mavzular bir-birining mavjudligi haqida bilishmaydi, shuning uchun ular shunchaki mavzu rejalashtiruvchisi ularga ajratgan vaqt ichida boshqarishi mumkin bo'lgan hamma narsani yozadilar. Kursning yaqinda o'tkazilgan ma'ruzasida bizda bu nimaga olib kelishi haqida bir misol bor edi, keling, buni eslaylik: Buning sababi shundaki, iplar umumiy resurs, konsol bilan, harakatlarni bir-biri bilan muvofiqlashtirmasdan ishlagan. Agar mavzu rejalashtiruvchisi Thread-1 ga vaqt ajratgan bo'lsa, u darhol hamma narsani konsolga yozadi. Boshqa mavzular allaqachon yozishga muvaffaq bo'lgan yoki yozishga vaqt topa olmaganligi muhim emas. Natija, ko'rib turganingizdek, halokatli. Shuning uchun ko'p bosqichli dasturlashda maxsus tushuncha kiritildi mutex (inglizcha "mutex", "o'zaro istisno" - "o'zaro istisno" dan). Muteks vazifasi- ma'lum bir vaqtda faqat bitta ip ob'ektga kirish huquqiga ega bo'lishi uchun mexanizmni taqdim eting. Agar Thread-1 A ob'ektining mutexini olgan bo'lsa, undagi biror narsani o'zgartirish uchun boshqa iplar unga kirish huquqiga ega bo'lmaydi. A ob'ektining mutexi chiqarilgunga qadar, qolgan iplar kutishga majbur bo'ladi. Haqiqiy hayotdan misol: tasavvur qiling-a, siz va yana 10 nafar notanish odam treningda qatnashmoqdasiz. Siz navbatma-navbat fikr bildirishingiz va biror narsani muhokama qilishingiz kerak. Ammo, siz bir-biringizni birinchi marta ko'rayotganingiz uchun, doimiy ravishda bir-biringizga xalaqit bermaslik va xafagarchilikka tushmaslik uchun siz "gapirish to'pi" qoidasidan foydalanasiz: faqat bitta odam gapira oladi - to'p bo'lgan kishi. uning qo'llari. Shunday qilib, muhokama adekvat va samarali bo'ladi. Demak, mutex, mohiyatiga ko'ra, shunday to'pdir. Agar ob'ektning mutexi bitta ipning qo'lida bo'lsa, boshqa iplar ob'ektga kira olmaydi. Muteks yaratish uchun hech narsa qilishingiz shart emas: u allaqachon Object sinfiga o'rnatilgan, ya'ni Java'dagi har bir ob'ektda bitta mavjud.

Sinxronlashtirilgan operator qanday ishlaydi

Keling, yangi kalit so'z bilan tanishamiz - sinxronlashtirilgan. Bu bizning kodimizning ma'lum bir qismini belgilaydi. Agar kod bloki sinxronlashtirilgan kalit so'z bilan belgilangan bo'lsa, bu blok bir vaqtning o'zida faqat bitta ip tomonidan bajarilishi mumkinligini anglatadi. Sinxronizatsiya turli yo'llar bilan amalga oshirilishi mumkin. Masalan, butun sinxronlashtirilgan usulni yarating: umumiy sinxronlashtirilgan void doSomething() () //...uslubiy mantiq) Yoki ba'zi ob'ektda sinxronlash amalga oshiriladigan kod blokini yozing: umumiy sinf Main ( private Object obj = new Object () ; public void doSomething () ( sinxronlashtirilgan (obj) ( ) ) ) Ma'nosi oddiy. Agar bitta ip sinxronlashtirilgan so'z bilan belgilangan kod blokiga kirsa, u bir zumda ob'ektning mutexiga ega bo'ladi va bir xil blok yoki usulga kirishga urinayotgan barcha boshqa iplar oldingi ip o'z ishini tugatguncha kutishga majbur bo'ladi. monitor. Aytmoqchi! Kurs ma'ruzalarida siz allaqachon sinxronlashtirilgan misollarni ko'rgansiz, lekin ular boshqacha ko'rinardi: ommaviy bekor almashtirish () ( sinxronlashtirilgan (bu) ( //...uslubiy mantiq) ) Mavzu siz uchun yangi va, albatta, avvaliga sintaksis bilan chalkashlik bo‘ladi. Shuning uchun, keyinchalik yozish usullarida adashmaslik uchun darhol eslab qoling. Ushbu ikki yozish usuli bir xil narsani anglatadi: ommaviy bekor almashtirish () ( sinxronlangan (bu) ( //...uslubiy mantiq) ) ommaviy sinxronlashtirilgan bekor almashtirish () ( ) ) Birinchi holda, siz usulga kirganingizdan so'ng darhol sinxronlashtirilgan kod blokini yaratasiz. U ushbu ob'ekt tomonidan, ya'ni joriy ob'ekt tomonidan sinxronlashtiriladi. Va ikkinchi misolda siz sinxronlashtirilgan so'zni butun usulga qo'yasiz. Endi sinxronizatsiya amalga oshiriladigan ob'ektni aniq ko'rsatishga hojat yo'q. Butun usul so'z bilan belgilangandan so'ng, bu usul avtomatik ravishda sinfning barcha ob'ektlari uchun sinxronlashtiriladi. Keling, qaysi usul yaxshiroq ekanligini muhokama qilmaylik. Hozircha o'zingizga ko'proq yoqqanini tanlang :) Eng asosiysi esda tuting: siz metodni uning ichidagi barcha mantiq bir vaqtning o'zida bitta ip tomonidan bajarilgandagina sinxronlangan deb e'lon qilishingiz mumkin. Misol uchun, bu holda doSomething() usulini sinxronlashtirish xato bo'ladi: public class Main ( private Object obj = new Object () ; public void doSomething () () //...ba'zi mantiq barcha mavzular uchun mavjud sinxronlangan (obj) ( //bir vaqtning o'zida faqat bitta mavzu uchun mavjud bo'lgan mantiq) ) ) Ko'rib turganingizdek, usulning bir qismi sinxronizatsiya talab qilinmaydigan mantiqni o'z ichiga oladi. Undagi kod bir vaqtning o'zida bir nechta iplar tomonidan bajarilishi mumkin va barcha muhim joylar alohida sinxronlashtirilgan blokga ajratilgan. Va bir daqiqa. Keling, mikroskop ostida o'z nomimizni ma'ruzadan almashtirish misolini ko'rib chiqaylik: ommaviy bekor almashtirish () ( sinxronlangan (bu) ( //...uslubiy mantiq } } Diqqat qilish: sinxronizatsiya shu yordamida amalga oshiriladi. Ya'ni, ma'lum bir MyClass ob'ektida. Tasavvur qiling-a, bizda 2 ta mavzu (Thread-1 va Thread-2) va faqat bitta MyClass myClass obyekti bor. Bunday holda, agar Thread-1 myClass.swap() usulini chaqirsa, ob'ektning mutexi band bo'ladi va Thread-2, myClass.swap() ga qo'ng'iroq qilishga urinayotganda, mutexning bo'sh bo'lishini kutib o'tirib qoladi. Agar bizda 2 ta ip va 2 ta MyClass ob'ekti bo'lsa - myClass1 va myClass2 - turli xil ob'ektlarda bizning iplarimiz bir vaqtning o'zida sinxronlashtirilgan usullarni osongina bajarishi mumkin. Birinchi ip bajariladi: myClass1. almashtirish (); Ikkinchisi: myClass2. almashtirish (); Bunday holda, swap() usuli ichidagi sinxronlangan kalit so'z dasturning ishlashiga ta'sir qilmaydi, chunki sinxronizatsiya ma'lum bir ob'ektda amalga oshiriladi. Va oxirgi holatda bizda 2 ta ob'ekt bor.Shuning uchun iplar bir-biriga muammo tug'dirmaydi. Hammasidan keyin; axiyri ikkita ob'ektda 2 xil mutex mavjud va ularning olinishi bir-biridan mustaqil.

Statik usullarda sinxronlashning xususiyatlari

Sinxronizatsiya qilish kerak bo'lsa, nima qilish kerak statik usul? sinf MyClass ( xususiy statik String name1 = "Olya" ; private static String name2 = "Lena" ; public static synchronized void swap () ( String s = name1; name1 = name2; name2 = s; ) ) Nima bo‘lishi aniq emas. bu holatda mutex rolini bajaring. Axir, biz allaqachon har bir ob'ektning mutexga ega ekanligiga qaror qildik. Ammo muammo shundaki, MyClass.swap() statik usulini chaqirish uchun bizga ob'ektlar kerak emas: usul statik! Va undan keyin nima? :/ Aslida, bu bilan hech qanday muammo yo'q. Java yaratuvchilari hamma narsaga g'amxo'rlik qilishdi :) Agar tanqidiy "ko'p oqimli" mantiqni o'z ichiga olgan usul statik bo'lsa, sinxronizatsiya sinf tomonidan amalga oshiriladi. Aniqlik uchun yuqoridagi kodni quyidagicha qayta yozish mumkin: sinf MyClass ( xususiy statik String name1 = "Olya" ; private static String name2 = "Lena" ; public static vioid swap () ( sinxronlashtirilgan (MyClass. class ) ( String s = name1 ; name1 = name2; name2 = s; ) ) ) Aslida, siz buni o'zingiz o'ylab ko'rishingiz mumkin edi: ob'ektlar yo'qligi sababli, sinxronizatsiya mexanizmi qandaydir tarzda sinflarning o'ziga "o'rnatilgan" bo'lishi kerak. Bu shunday: siz sinflar bo'ylab ham sinxronlashtirishingiz mumkin.