Ngationei kuti hurongwa hunoshanda panguva imwe chete uye hunofambirana sei mu.Net, tichishandisa Philosophers Dining Problem semuenzaniso. Chirongwa ndeichi, kubva pakuwiriranisa kwetambo / maitiro, kune mutambi modhi (mune zvikamu zvinotevera). Nyaya yacho inogona kubatsira kune wekutanga kuzivana kana kuti kumutsiridza ruzivo rwako.
Sei uchizviita zvachose? MaTransistors anosvika pakukura kwavo, mutemo waMoore unogara pakudzikama kwekumhanya kwechiedza uye saka kuwedzera kunoonekwa muhuwandu, mamwe ma transistors anogona kuitwa. Panguva imwecheteyo, huwandu hwe data huri kukura, uye vashandisi vanotarisira mhinduro yekukurumidza kubva kune masisitimu. Mumamiriro ezvinhu akadaro, "yakajairika" hurongwa, kana isu tine imwe tambo yekuuraya, haichashandi. Iwe unofanirwa neimwe nzira kugadzirisa dambudziko rekuita panguva imwe chete kana panguva imwe chete. Uyezve, dambudziko iri riripo pamatanho akasiyana: pamwero wetambo, pamwero wemaitiro, pamwero wemashini mune network (yakagoverwa masisitimu). .NET ine yepamusoro-soro, yakaedzwa nguva-yakaedzwa matekinoroji ekukurumidza uye nemazvo kugadzirisa matambudziko akadaro.
Basa
Edsger Dijkstra akaisa dambudziko iri kuvadzidzi vake kare kare muna 1965. Iyo yakagadzirwa yakagadziriswa ndeyotevera. Pane imwe (kazhinji shanu) nhamba yevazivi uye nhamba imwechete yeforogo. Vanogara patafura yeraundi, forogo pakati pavo. Vazivi vanogona kudya kubva mundiro dzavo dzechikafu chisingaperi, funga kana kumirira. Kuti udye muzivi, unofanira kutora maforogo maviri (yekupedzisira anogovera forogo neyokutanga). Kunhonga nekuisa pasi forogo zvinhu zviviri zvakasiyana. Vese vazivi vakanyarara. Basa nderekutsvaga algorithm yekuti vese vaizofunga uye vazere kunyangwe mushure memakore makumi mashanu nemana.
Kutanga, ngatiedzei kugadzirisa dambudziko iri kuburikidza nekushandisa nzvimbo yakagovaniswa. Maforogo akarara patafura yakajairika uye vazivi vanongoatora pavanenge vari voadzosera. Pano pane matambudziko nekuyananisa, nguva chaiyo yekutora surebets? ko kana pasina forogo? etc. Asi kutanga, ngatitangei vazivi.
Kutanga shinda, tinoshandisa dziva reshinda Task.Run
nzira:
var cancelTokenSource = new CancellationTokenSource();
Action<int> create = (i) => RunPhilosopher(i, cancelTokenSource.Token);
for (int i = 0; i < philosophersAmount; i++)
{
int icopy = i;
// ΠΠΎΠΌΠ΅ΡΡΠΈΡΡ Π·Π°Π΄Π°ΡΡ Π² ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΠΏΡΠ»Π° ΠΏΠΎΡΠΎΠΊΠΎΠ². ΠΠ΅ΡΠΎΠ΄ RunDeadlock Π½Π΅ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΡΡΡΡ
// ΡΡΠ°Π·Ρ, Π° ΠΆΠ΄Π΅Ρ ΡΠ²ΠΎΠ΅Π³ΠΎ ΠΏΠΎΡΠΎΠΊΠ°. ΠΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΠΉ Π·Π°ΠΏΡΡΠΊ.
philosophers[i] = Task.Run(() => create(icopy), cancelTokenSource.Token);
}
Dziva reshinda rakagadzirirwa kukwenenzvera kugadzira shinda uye kudzima. Dziva iri rine mutsetse une mabasa uye CLR inogadzira kana kubvisa shinda zvichienderana nehuwandu hwemabasa aya. Dziva rimwe kune ese maAppDomains. Iri dziva rinofanira kushandiswa zvinenge nguva dzose, nokuti. hapana chikonzero chekunetseka nekugadzira, kudzima tambo, mitsetse yavo, nezvimwe. Zvinogoneka pasina dziva, asi zvino unofanirwa kuishandisa zvakananga. Thread
, izvi zvinobatsira kune zviitiko kana iwe uchida kushandura kukoshesa kwetambo, kana tine kushanda kwenguva refu, kune Foreground thread, nezvimwewo.
Mune mamwe mazwi, System.Threading.Tasks.Task
kirasi yakafanana Thread
, asi nemhando dzese dzakareruka: kugona kuita basa mushure mekuvhara kwemamwe mabasa, kuvadzosa kubva kumabasa, zviri nyore kuvakanganisa, nezvimwe. etc. Zvinodiwa kutsigira async / kumirira zvivakwa (Task-based Asynchronous Pattern, syntactic sugar yekumirira IO operations). Tichazotaura nezvazvo gare gare.
CancelationTokenSource
apa panodiwa kuti shinda ikwanise kugumira pachiratidzo cheshinda yekudaidza.
Sync Matambudziko
Vakavharirwa Vazivi
Zvakanaka, tinoziva kugadzira shinda, ngatiedzei kudya masikati:
// ΠΡΠΎ ΠΊΠ°ΠΊΠΈΠ΅ Π²ΠΈΠ»ΠΊΠΈ Π²Π·ΡΠ». Π ΠΏΡΠΈΠΌΠ΅ΡΡ: 1 1 3 3 - 1ΠΉ ΠΈ 3ΠΉ Π²Π·ΡΠ»ΠΈ ΠΏΠ΅ΡΠ²ΡΠ΅ Π΄Π²Π΅ ΠΏΠ°ΡΡ.
private int[] forks = Enumerable.Repeat(0, philosophersAmount).ToArray();
// Π’ΠΎ ΠΆΠ΅, ΡΡΠΎ RunPhilosopher()
private void RunDeadlock(int i, CancellationToken token)
{
// ΠΠ΄Π°ΡΡ Π²ΠΈΠ»ΠΊΡ, Π²Π·ΡΡΡ Π΅Ρ. ΠΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½ΡΠ½ΠΎ:
// while(true)
// if forks[fork] == 0
// forks[fork] = i+1
// break
// Thread.Sleep() ΠΈΠ»ΠΈ Yield() ΠΈΠ»ΠΈ SpinWait()
void TakeFork(int fork) =>
SpinWait.SpinUntil(() =>
Interlocked.CompareExchange(ref forks[fork], i+1, 0) == 0);
// ΠΠ»Ρ ΠΏΡΠΎΡΡΠΎΡΡ, Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Ρ Interlocked.Exchange:
void PutFork(int fork) => forks[fork] = 0;
while (true)
{
TakeFork(Left(i));
TakeFork(Right(i));
eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
PutFork(Left(i));
PutFork(Right(i));
Think(i);
// ΠΠ°Π²Π΅ΡΡΠΈΡΡ ΡΠ°Π±ΠΎΡΡ ΠΏΠΎ-Ρ
ΠΎΡΠΎΡΠ΅ΠΌΡ.
token.ThrowIfCancellationRequested();
}
}
Pano isu tinotanga kuedza kutora forogo yekuruboshwe, uye ipapo iyo yakarurama, uye kana ikashanda, saka tinodya uye tinovadzorera zvakare. Kutora forogo imwe atomic, i.e. shinda mbiri haigoni kutora imwe panguva imwe chete (isina kururama: yekutanga inoverenga kuti forogo yakasununguka, yechipiri - zvakare, yekutanga inotora, yechipiri inotora). Nokuda kweizvi Interlocked.CompareExchange
, iyo inofanirwa kuitwa nemirairo ye processor (TSL
, XCHG
), iyo inokiya chidimbu chendangariro chekuverenga nekunyorwa kweatomu. Uye SpinWait yakaenzana nekuvaka while(true)
chete ne "mashiripiti" mashoma - tambo inotora processor (Thread.SpinWait
), asi dzimwe nguva inoendesa kutonga kune imwe shinda (Thread.Yeild
) kana kurara (Thread.Sleep
).
Asi mhinduro iyi haishande, nekuti iyo inoyerera nekukurumidza (kwandiri mukati mesekondi) yakavharwa: vese vazivi vanotora yavo yekuruboshwe forogo, asi kwete iyo chaiyo. The forks array zvino ine zvakakosha: 1 2 3 4 5.
Mumufananidzo, kuvhara tambo (deadlock). Green - kuuraya, tsvuku - kuwiriranisa, grey - shinda iri kurara. Iyo rhombuses inoratidza nguva yekutanga yeMabasa.
Nzara yevazivi
Kunyangwe zvisingakodzeri kufunga zvakanyanya chikafu, asi nzara inoita kuti chero munhu arege uzivi. Ngatiedzei kutevedzera mamiriro enzara yeshinda mudambudziko redu. Nzara ndeye apo tambo iri kushanda, asi pasina basa rakakosha, nemamwe mazwi, iyi ndiyo imwechete yakafa, chete ikozvino tambo haisi kurara, asi iri kushingaira kutsvaga chimwe chinhu chekudya, asi hapana chikafu. Kuti tidzivise kuvharika kazhinji, tinodzosera forogo kumashure kana tikatadza kutora imwe.
// Π’ΠΎ ΠΆΠ΅ ΡΡΠΎ ΠΈ Π² RunDeadlock, Π½ΠΎ ΡΠ΅ΠΏΠ΅ΡΡ ΠΊΠ»Π°Π΄Π΅ΠΌ Π²ΠΈΠ»ΠΊΡ Π½Π°Π·Π°Π΄ ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ ΠΏΠ»ΠΎΡ
ΠΈΡ
ΡΠΈΠ»ΠΎΡΠΎΡΠΎΠ².
private void RunStarvation(int i, CancellationToken token)
{
while (true)
{
bool hasTwoForks = false;
var waitTime = TimeSpan.FromMilliseconds(50);
// ΠΠ»ΠΎΡ
ΠΎΠΉ ΡΠΈΠ»ΠΎΡΠΎΡΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ ΡΠΆΠ΅ ΠΈΠΌΠ΅ΡΡ Π²ΠΈΠ»ΠΊΡ:
bool hasLeft = forks[Left(i)] == i + 1;
if (hasLeft || TakeFork(Left(i), i + 1, waitTime))
{
if (TakeFork(Right(i), i + 1, TimeSpan.Zero))
hasTwoForks = true;
else
PutFork(Left(i)); // ΠΠ½ΠΎΠ³Π΄Π° ΠΏΠ»ΠΎΡ
ΠΎΠΉ ΡΠΈΠ»ΠΎΡΠΎΡ ΠΎΡΠ΄Π°Π΅Ρ Π²ΠΈΠ»ΠΊΡ Π½Π°Π·Π°Π΄.
}
if (!hasTwoForks)
{
if (token.IsCancellationRequested) break;
continue;
}
eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
bool goodPhilosopher = i % 2 == 0;
// Π ΠΏΠ»ΠΎΡ
ΠΎΠΉ ΡΠΈΠ»ΠΎΡΠΎΡ Π·Π°Π±ΡΠ²Π°Π΅Ρ ΠΏΠΎΠ»ΠΎΠΆΠΈΡΡ ΡΠ²ΠΎΡ Π²ΠΈΠ»ΠΊΡ ΠΎΠ±ΡΠ°ΡΠ½ΠΎ:
if (goodPhilosopher)
PutFork(Left(i));
// Π Π΅ΡΠ»ΠΈ ΠΈ ΠΏΡΠ°Π²ΡΡ Π½Π΅ ΠΏΠΎΠ»ΠΎΠΆΠΈΡ, ΡΠΎ Ρ
ΠΎΡΠΎΡΠΈΠ΅ Π±ΡΠ΄ΡΡ Π²ΠΎΠΎΠ±ΡΠ΅ Π±Π΅Π· Π΅Π΄Ρ.
PutFork(Right(i));
Think(i);
if (token.IsCancellationRequested)
break;
}
}
// Π’Π΅ΠΏΠ΅ΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΠΆΠ΄Π°ΡΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ.
bool TakeFork(int fork, int philosopher, TimeSpan? waitTime = null)
{
return SpinWait.SpinUntil(
() => Interlocked.CompareExchange(ref forks[fork], philosopher, 0) == 0,
waitTime ?? TimeSpan.FromMilliseconds(-1)
);
}
Chinhu chakakosha pamusoro pekodhi iyi ndechekuti vaviri kubva pavana vazivi vanokanganwa kuisa pasi yavo yekuruboshwe forogo. Uye zvinoitika kuti vanodya chikafu chakawanda, asi vamwe vanotanga kufa nenzara, kunyange zvazvo tambo dzichinyanya kukosha. Pano havasi kuziya nenzara zvachose, nokuti. vazivi vakaipa vanoisa maforogo avo kumashure dzimwe nguva. Zvinoitika kuti vanhu vakanaka vanodya kanenge ka5 zvishoma pane zvakaipa. Saka chikanganiso chidiki mukodhi chinotungamira mukudonha kwekuita. Zvakakoshawo kuziva pano kuti mamiriro ezvinhu asingawanzoitiki anokwanisika apo vose vazivi vanotora forogo yekuruboshwe, hapana yakarurama, vanoisa kuruboshwe, kumirira, kutora kuruboshwe zvakare, nezvimwewo. Mamiriro ezvinhu aya zvakare inzara, kufanana nekufa. Ndakatadza kuzvidzokorora. Pasi pane mufananidzo wemamiriro ezvinhu apo mafirosofi maviri akaipa akatora maforogo maviri uye maviri akanaka ari kufa nenzara.
Pano iwe unogona kuona kuti tambo dzinomuka dzimwe nguva uye edza kutora sosi. Maviri emakona mana haaite chinhu (girinhi girafu pamusoro).
Kufa kweMuzivi
Zvakanaka, rimwe dambudziko rinogona kukanganisa kudya kwemanheru kune mbiri yevazivi kana mumwe wavo akafa kamwe kamwe aine maforogo mumaoko ake (uye ivo vachamuviga zvakadaro). Ipapo vavakidzani vachasara vasina kudya kwemanheru. Iwe unogona kuuya nekodhi yemuenzaniso yenyaya iyi iwe pachako, semuenzaniso, inokandwa kunze NullReferenceException
mushure mekunge muzivi atora maforogo. Uye, nenzira, iyo yakasarudzika haizobatwa uye iyo yekufona kodhi haingoibata (yeizvi AppDomain.CurrentDomain.UnhandledException
uye etc.). Naizvozvo, vanobata kukanganisa vanodiwa mushinda pachayo uye nekugumisira kwakanaka.
Waiter
Zvakanaka, tinogadzirisa sei dambudziko iri rekufa, nzara, uye rufu? Tichabvumira muzivi mumwe chete kuti asvike maforogo, wedzera kusabatanidzwa kwetambo dzenzvimbo ino. Kuzviita sei? Ngatitii pane weta pedyo nevazivi anopa mvumo kune chero muzivi kuti atore maforogo. Tinoita sei muchengeti uyu uye kuti vazivi vachamubvunza sei, mibvunzo inonakidza.
Nzira iri nyore ndeye apo vazivi vanongogara vachibvunza weta kuti awane maforogo. Avo. zvino vazivi havazomirira forogo pedyo, asi mirira kana kubvunza weta. Pakutanga, isu tinoshandisa chete Mushandisi Nzvimbo yeizvi, mairi isu hatishandise kukanganisa kudaidza chero maitiro kubva kukernel (pamusoro pavo pazasi).
Mhinduro munzvimbo yemushandisi
Pano tichaita zvakafanana sezvataimboita neforogo imwe chete nevazivi vaviri, isu tichatenderera mukutenderera uye kumirira. Asi zvino zvichava zvose vazivi uye, sokunge zvakadaro, imwe chete forogo, i.e. zvinogona kutaurwa kuti muzivi chete akatora iyi "forogo yegoridhe" kubva kune weta achadya. Kune izvi isu tinoshandisa SpinLock.
private static SpinLock spinLock = new SpinLock(); // ΠΠ°Ρ "ΠΎΡΠΈΡΠΈΠ°Π½Ρ"
private void RunSpinLock(int i, CancellationToken token)
{
while (true)
{
// ΠΠ·Π°ΠΈΠΌΠ½Π°Ρ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠ° ΡΠ΅ΡΠ΅Π· busy waiting. ΠΡΠ·ΡΠ²Π°Π΅ΠΌ Π΄ΠΎ try, ΡΡΠΎΠ±Ρ
// Π²ΡΠ±ΡΠ°ΡΠΈΡΡ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π² ΡΠ»ΡΡΠ°Π΅ ΠΎΡΠΈΠ±ΠΊΠΈ Π² ΡΠ°ΠΌΠΎΠΌ SpinLock.
bool hasLock = false;
spinLock.Enter(ref hasLock);
try
{
// ΠΠ΄Π΅ΡΡ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΎΠ΄ΠΈΠ½ ΠΏΠΎΡΠΎΠΊ (mutual exclusion).
forks[Left(i)] = i + 1; // ΠΠ΅ΡΠ΅ΠΌ Π²ΠΈΠ»ΠΊΡ ΡΡΠ°Π·Ρ, Π±Π΅Π· ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ.
forks[Right(i)] = i + 1;
eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
forks[Left(i)] = 0;
forks[Right(i)] = 0;
}
finally
{
if(hasLock) spinLock.Exit(); // ΠΠ·Π±Π΅Π³Π°Π΅ΠΌ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ ΡΠΎ ΡΠΌΠ΅ΡΡΡΡ ΡΠΈΠ»ΠΎΡΠΎΡΠ°.
}
Think(i);
if (token.IsCancellationRequested)
break;
}
}
SpinLock
ichi chivharo, chine, kutaura, zvakafanana while(true) { if (!lock) break; }
, asi nemamwe "mashiripiti" kupfuura mukati SpinWait
(iyo inoshandiswa ipapo). Iye zvino anoziva kuverenga vaya vakamirira, ovararisa zvishoma, uye nezvimwe zvakawanda. etc. Kazhinji, anoita zvose zvinobvira kuti optimize. Asi isu tinofanira kuyeuka kuti ichi chichiri chimwechete chinoshanda chinodya processor zviwanikwa uye inochengetedza kuyerera, izvo zvinogona kutungamira kunzara kana mumwe wevazivi akave pamberi kupfuura vamwe, asi asina forogo yegoridhe (Priority Inversion dambudziko) . Naizvozvo, isu tinoishandisa chete kune pfupi pfupi shanduko mundangariro yakagovaniswa, pasina kana yechitatu-bato mafoni, nested makiyi, uye zvimwe zvinoshamisa.
Kudhirowa kwe SpinLock
. Hova dzinogara "dzichirwira" forogo yegoridhe. Pane kukundikana - mumufananidzo, nzvimbo yakasarudzwa. Iwo macores haashandiswe zvizere: chete angangoita 2/3 neshinda ina idzi.
Imwe mhinduro pano ingave yekushandisa chete Interlocked.CompareExchange
nekumirira kumwechete kunoshanda sezvakaratidzwa mukodhi iri pamusoro (mune vazivi vane nzara), asi izvi, sezvatotaurwa, zvinogona kutungamirira kukuvhara.
pamusoro Interlocked
Zvinofanira kucherechedzwa kuti hapana chete CompareExchange
, asiwo dzimwe nzira dzeatomu yekuverenga UYE kunyora. Uye kuburikidza nekudzokorora kwekuchinja, kana imwe tambo iine nguva yekuita shanduko yayo (verenga 1, verenga 2, nyora 2, nyora 1 yakaipa), inogona kushandiswa kune dzakaoma shanduko kune imwechete kukosha (Interlocked Anything pattern) .
Kernel Mode Solutions
Kuti tisapambadze zviwanikwa muchiuno, ngationei kuti tingavharisa sei shinda. Nemamwe mashoko, tichienderera mberi nemuenzaniso wedu, ngationei kuti weta anorarisa sei muzivi ndokumumutsa chete pazvinenge zvakakodzera. Kutanga, ngatitarisei maitiro ekuita izvi kuburikidza ne kernel modhi yeiyo inoshanda sisitimu. Zvese zvimiro zviripo kazhinji zvinononoka pane izvo zviri munzvimbo yemushandisi. Kanoverengeka zvishoma nezvishoma, semuenzaniso AutoResetEvent
pamwe 53 nguva zvishoma nezvishoma SpinLock
[Richter]. Asi nerubatsiro rwavo, unogona kuwiriranisa maitiro mukati mese system, inotungamirwa kana kwete.
Iyo yakakosha kuvaka pano ndiyo semaphore yakakurudzirwa naDijkstra anopfuura hafu yezana ramakore rapfuura. Semaphore iri, nekungoiswa, yakanaka integer inotungamirwa nesystem, uye maviri maoperation pairi, kuwedzera uye kudzikira. Kana ikatadza kudzikira, zero, ipapo tambo yekufona inovharwa. Kana iyo nhamba ichiwedzerwa neimwe tambo inoshanda/maitiro, ipapo tambo dzinosvetuka uye semaphore inodzikiswa zvakare nenhamba yakapfuura. Mumwe anogona kufungidzira zvitima mubhodhoro rine semaphore. .NET inopa akawanda anovaka ane mashandiro akafanana: AutoResetEvent
, ManualResetEvent
, Mutex
uye neni Semaphore
. Tichashandisa AutoResetEvent
, iyi ndiyo yakapfava yezvivakwa izvi: maviri chete maitiro 0 uye 1 (manyepo, echokwadi). Her Method WaitOne()
inovharira tambo yekufona kana kukosha kwaive 0, uye kana 1, inodzikisira kuenda ku0 uye kuisvetuka. Nzira Set()
inosimudza kusvika pa1 uye inoregedza weta mumwe chete, anodzika zvakare kusvika ku0. Inoita senzira yepasi pevhu.
Ngatiomese mhinduro uye tishandise kukiya kune mumwe nemumwe muzivi, uye kwete zvese kamwechete. Avo. zvino panogona kuva nevazivi vakawanda panguva imwe chete, uye kwete mumwe. Asi isu zvakare tinovharira kupinda patafura kuitira kuti tiite nemazvo, kudzivirira nhangemutange (madzinza mamiriro), tora surebets.
// ΠΠ»Ρ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠΈΠ»ΠΎΡΠΎΡΠ°.
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΡΡΡ: new AutoResetEvent(true) Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ.
private AutoResetEvent[] philosopherEvents;
// ΠΠ»Ρ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ Π²ΠΈΠ»ΠΊΠ°ΠΌ / Π΄ΠΎΡΡΡΠΏ ΠΊ ΡΡΠΎΠ»Ρ.
private AutoResetEvent tableEvent = new AutoResetEvent(true);
// Π ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ ΡΠΈΠ»ΠΎΡΠΎΡΠ°.
public void Run(int i, CancellationToken token)
{
while (true)
{
TakeForks(i); // ΠΠ΄Π΅Ρ Π²ΠΈΠ»ΠΊΠΈ.
// ΠΠ±Π΅Π΄. ΠΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΈ Π΄ΠΎΠ»ΡΡΠ΅.
eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
PutForks(i); // ΠΡΠ΄Π°ΡΡ Π²ΠΈΠ»ΠΊΠΈ ΠΈ ΡΠ°Π·Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°ΡΡ ΡΠΎΡΠ΅Π΄Π΅ΠΉ.
Think(i);
if (token.IsCancellationRequested) break;
}
}
// ΠΠΆΠΈΠ΄Π°ΡΡ Π²ΠΈΠ»ΠΊΠΈ Π² Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠ΅.
void TakeForks(int i)
{
bool hasForks = false;
while (!hasForks) // ΠΠΎΠΏΡΠΎΠ±ΠΎΠ²Π°ΡΡ Π΅ΡΠ΅ ΡΠ°Π· (Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠ° Π½Π΅ Π·Π΄Π΅ΡΡ).
{
// ΠΡΠΊΠ»ΡΡΠ°ΡΡΠΈΠΉ Π΄ΠΎΡΡΡΠΏ ΠΊ ΡΡΠΎΠ»Ρ, Π±Π΅Π· Π³ΠΎΠ½ΠΎΠΊ Π·Π° Π²ΠΈΠ»ΠΊΠ°ΠΌΠΈ.
tableEvent.WaitOne();
if (forks[Left(i)] == 0 && forks[Right(i)] == 0)
forks[Left(i)] = forks[Right(i)] = i + 1;
hasForks = forks[Left(i)] == i + 1 && forks[Right(i)] == i + 1;
if (hasForks)
// Π’Π΅ΠΏΠ΅ΡΡ ΡΠΈΠ»ΠΎΡΠΎΡ ΠΏΠΎΠ΅ΡΡ, Π²ΡΠΉΠ΄Π΅Ρ ΠΈΠ· ΡΠΈΠΊΠ»Π°. ΠΡΠ»ΠΈ Set
// Π²ΡΠ·Π²Π°Π½ Π΄Π²Π°ΠΆΠ΄Ρ, ΡΠΎ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ true.
philosopherEvents[i].Set();
// Π Π°Π·Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°ΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΎΠΆΠΈΠ΄Π°ΡΡΠ΅Π³ΠΎ. ΠΠΎΡΠ»Π΅ Π½Π΅Π³ΠΎ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ tableEvent Π² false.
tableEvent.Set();
// ΠΡΠ»ΠΈ ΠΈΠΌΠ΅Π΅Ρ true, Π½Π΅ Π±Π»ΠΎΠΊΠΈΡΡΠ΅ΡΡΡ, Π° Π΅ΡΠ»ΠΈ false, ΡΠΎ Π±ΡΠ΄Π΅Ρ ΠΆΠ΄Π°ΡΡ Set ΠΎΡ ΡΠΎΡΠ΅Π΄Π°.
philosopherEvents[i].WaitOne();
}
}
// ΠΡΠ΄Π°ΡΡ Π²ΠΈΠ»ΠΊΠΈ ΠΈ ΡΠ°Π·Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°ΡΡ ΡΠΎΡΠ΅Π΄Π΅ΠΉ.
void PutForks(int i)
{
tableEvent.WaitOne(); // ΠΠ΅Π· Π³ΠΎΠ½ΠΎΠΊ Π·Π° Π²ΠΈΠ»ΠΊΠ°ΠΌΠΈ.
forks[Left(i)] = 0;
// ΠΡΠΎΠ±ΡΠ΄ΠΈΡΡ Π»Π΅Π²ΠΎΠ³ΠΎ, Π° ΠΏΠΎΡΠΎΠΌ ΠΈ ΠΏΡΠ°Π²ΠΎΠ³ΠΎ ΡΠΎΡΠ΅Π΄Π°, Π»ΠΈΠ±ΠΎ AutoResetEvent Π² true.
philosopherEvents[LeftPhilosopher(i)].Set();
forks[Right(i)] = 0;
philosopherEvents[RightPhilosopher(i)].Set();
tableEvent.Set();
}
Kuti unzwisise zviri kuitika pano, funga nyaya apo muzivi akakundikana kutora maforogo, ipapo zviito zvake zvichava zvinotevera. Akamirira kusvika patafura. Arigamuchira, anoedza kutora maforogo. Hazvina kushanda. Inopa mukana kune tafura (mutual exclusion). Uye anopfuura "turntile" yake (AutoResetEvent
) (vanotanga kuvhurika). Inopinda mudenderedzwa zvakare, nekuti haana maforogo. Anoedza kuvatora omira pa "turnstile" yake. Mumwe muvakidzani ane rombo rakanaka kurudyi kana kuruboshwe, apedza kudya, anovhura muzivi wedu, "kuvhura turnstile yake." Muzivi wedu anoipfuura (uye inovhara kumashure kwayo) kechipiri. Anoedza kechitatu kutora maforogo. Rombo rakanaka. Uye anopfuudza chijana chake kuti adye.
Kana paine zvikanganiso zvisina kujairika mukodhi yakadaro (inogara iripo), semuenzaniso, muvakidzani anotsanangurwa zvisiri izvo kana chinhu chimwe chete chakasikwa. AutoResetEvent
kune vese (Enumerable.Repeat
), ipapo vazivi vachange vakamirira vanogadzira, nekuti Kutsvaga zvikanganiso mukodhi yakadaro ibasa rakaoma. Rimwe dambudziko nemhinduro iyi nderekuti harivimbisi kuti mumwe muzivi haazonzwe nzara.
Hybrid Solutions
Takatarisa nzira mbiri dzekutora nguva, patinogara mushandisi modhi uye loop, uye patinovhara tambo kuburikidza nekernel. Nzira yekutanga yakanaka kune zvivharo zvipfupi, yechipiri kune yakareba. Zvinowanzodikanwa kutanga muchidimbu kumirira kuti shanduko ichinje muchiuno, uye wozovhara tambo kana kumirira kwakareba. Iyi nzira inoshandiswa mune inonzi. hybrid structures. Heano akafanana ekuvaka senge kernel modhi, asi ikozvino ine mushandisi modhi loop: SemaphorSlim
, ManualResetEventSlim
etc. Iyo inonyanya kufarirwa dhizaini pano Monitor
, nokuti muC# pane inozivikanwa lock
syntax. Monitor
iyi ndiyo yakafanana semaphore ine huwandu hunokosha hwe1 (mutex), asi nerutsigiro rwekumirira mu loop, recursion, the Condition Variable pattern (zvimwe pane iyo pazasi), nezvimwewo. Ngatitarisei mhinduro nayo.
// Π‘ΠΏΡΡΡΠ΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡ Π΄Π»Ρ ΠΠΎΠ½ΠΈΡΠΎΡΠ° ΠΎΡ Π²ΡΠ΅Ρ
, ΡΡΠΎΠ±Ρ Π±Π΅Π· Π΄Π΅Π΄Π»ΠΎΠΊΠΎΠ².
private readonly object _lock = new object();
// ΠΡΠ΅ΠΌΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ ΠΏΠΎΡΠΎΠΊΠ°.
private DateTime?[] _waitTimes = new DateTime?[philosophersAmount];
public void Run(int i, CancellationToken token)
{
while (true)
{
TakeForks(i);
eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
PutForks(i);
Think(i);
if (token.IsCancellationRequested) break;
}
}
// ΠΠ°ΡΠ΅ ΡΠ»ΠΎΠΆΠ½ΠΎΠ΅ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ Π΄Π»Ρ Condition Variable ΠΏΠ°ΡΡΠ΅ΡΠ½Π°.
bool CanIEat(int i)
{
// ΠΡΠ»ΠΈ Π΅ΡΡΡ Π²ΠΈΠ»ΠΊΠΈ:
if (forks[Left(i)] != 0 && forks[Right(i)] != 0)
return false;
var now = DateTime.Now;
// ΠΠΎΠΆΠ΅Ρ, Π΅ΡΠ»ΠΈ ΡΠΎΡΠ΅Π΄ΠΈ Π½Π΅ Π±ΠΎΠ»Π΅Π΅ Π³ΠΎΠ»ΠΎΠ΄Π½ΡΠ΅, ΡΠ΅ΠΌ ΡΠ΅ΠΊΡΡΠΈΠΉ.
foreach(var p in new int[] {LeftPhilosopher(i), RightPhilosopher(i)})
if (_waitTimes[p] != null && now - _waitTimes[p] > now - _waitTimes[i])
return false;
return true;
}
void TakeForks(int i)
{
// ΠΠ°ΠΉΡΠΈ Π² ΠΠΎΠ½ΠΈΡΠΎΡ. Π’ΠΎ ΠΆΠ΅ ΡΠ°ΠΌΠΎΠ΅: lock(_lock) {..}.
// ΠΡΠ·ΡΠ²Π°Π΅ΠΌ Π²Π½Π΅ try, ΡΡΠΎΠ±Ρ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΡΠ±ΡΠ°ΡΡΠ²Π°Π»ΠΎΡΡ Π²ΡΡΠ΅.
bool lockTaken = false;
Monitor.Enter(_lock, ref lockTaken);
try
{
_waitTimes[i] = DateTime.Now;
// Condition Variable ΠΏΠ°ΡΡΠ΅ΡΠ½. ΠΡΠ²ΠΎΠ±ΠΎΠΆΠ΄Π°Π΅ΠΌ Π»ΠΎΠΊ, Π΅ΡΠ»ΠΈ Π½Π΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½Π½ΠΎ
// ΡΠ»ΠΎΠΆΠ½ΠΎΠ΅ ΡΡΠ»ΠΎΠ²ΠΈΠ΅. Π ΠΆΠ΄Π΅ΠΌ ΠΏΠΎΠΊΠ° ΠΊΡΠΎ-Π½ΠΈΠ±ΡΠ΄Ρ ΡΠ΄Π΅Π»Π°Π΅Ρ Pulse / PulseAll.
while (!CanIEat(i))
Monitor.Wait(_lock);
forks[Left(i)] = i + 1;
forks[Right(i)] = i + 1;
_waitTimes[i] = null;
}
finally
{
if (lockTaken) Monitor.Exit(_lock);
}
}
void PutForks(int i)
{
// Π’ΠΎ ΠΆΠ΅ ΡΠ°ΠΌΠΎΠ΅: lock (_lock) {..}.
bool lockTaken = false;
Monitor.Enter(_lock, ref lockTaken);
try
{
forks[Left(i)] = 0;
forks[Right(i)] = 0;
// ΠΡΠ²ΠΎΠ±ΠΎΠ΄ΠΈΡΡ Π²ΡΠ΅ ΠΏΠΎΡΠΎΠΊΠΈ Π² ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ ΠΠΠ‘ΠΠ Π²ΡΠ·ΠΎΠ²Π° Monitor.Exit.
Monitor.PulseAll(_lock);
}
finally
{
if (lockTaken) Monitor.Exit(_lock);
}
}
Pano tiri kuvharisa zvakare tafura yese kuti tiwane maforogo, asi ikozvino tiri kuvhura tambo dzese kamwechete, uye kwete vavakidzani kana munhu apedza kudya. Avo. kutanga, mumwe munhu anodya uye anovhara vavakidzani, uye kana uyu munhu apedza, asi anoda kudya zvakare pakarepo, anopinda mukuvhara uye anomutsa vavakidzani vake, nokuti. nguva yayo yekumirira ishoma.
Iyi ndiyo nzira yatinodzivisa nayo kufa uye nzara yemumwe muzivi. Isu tinoshandisa loop yekumirira kwenguva pfupi uye kuvhara tambo kwenguva refu. Kusunungura munhu wese kamwechete kunononoka kupfuura dai muvakidzani chete akavhurwa, semumhinduro AutoResetEvent
, asi musiyano haufaniri kuva mukuru, nokuti shinda dzinofanira kugara dziri mushandisi mode kutanga.
Π£ lock
syntax ine zvinoshamisa zvinoshamisa. Zvinokurudzira kushandisa Monitor
zvakananga [Richter] [Eric Lippert]. Chimwe chazvo ndechokuti lock
nguva dzose kunze Monitor
, kunyangwe paive nemusiyano, mune iyo nyaya imwe shinda inogona kushandura yakagovaniswa memory state. Mumamiriro ezvinhu akadaro, kazhinji zviri nani kuenda kune deadlock kana neimwe nzira kumisa chirongwa zvakachengeteka. Chimwe chishamiso ndechekuti Monitor inoshandisa mabhuroko ekuyananisa (SyncBlock
), izvo zviripo muzvinhu zvese. Naizvozvo, kana chinhu chisina kufanira chakasarudzwa, unogona nyore kuwana deadlock (somuenzaniso, kana iwe ukakiya pane yakavharirwa tambo). Isu tinoshandisa chinhu chakavanzika nguva dzose kune izvi.
Iyo Condition Variable pateni inobvumidza iwe kuti unyatso kuita tarisiro yeimwe yakaoma mamiriro. MuNET, haina kukwana, mumaonero angu, nekuti mudzidziso, panofanirwa kuve nemitsara yakati wandei pane akati wandei (semuPosix Threads), uye kwete pane imwe lok. Ipapo mumwe aigona kuzviita kune vese vazivi. Asi kunyange mune iyi fomu, inokubvumira kuderedza kodhi.
vazivi vakawanda kana async
/ await
Zvakanaka, ikozvino tinogona kuvharira tambo. Asi zvakadini kana tine vazivi vakawanda? 100? 10000? Semuenzaniso, takagamuchira 100000 zvikumbiro kuwebhu server. Ichave pamusoro kugadzira tambo yechikumbiro chega chega, nekuti saka shinda dzakawanda hadzizomhanye dzakafanana. Inongomhanya yakawanda sekunge paine zvine musoro cores (ini ndine 4). Uye vamwe vese vachangobvisa zviwanikwa. Imwe mhinduro kudambudziko iri ndeye async / yekumirira pateni. Pfungwa yaro ndeyekuti basa haribate shinda kana ichida kumirira kuti chimwe chinhu chienderere mberi. Uye kana ikaita chimwe chinhu, inotangazve kuurayiwa kwayo (asi kwete patambo imwechete!). Kwatiri isu tichamirira forogo.
SemaphoreSlim
ane izvi WaitAsync()
nzira. Heino kuitisa uchishandisa iyi pateni.
// ΠΠ°ΠΏΡΡΠΊ ΡΠ°ΠΊΠΎΠΉ ΠΆΠ΅, ΠΊΠ°ΠΊ ΡΠ°Π½ΡΡΠ΅. ΠΠ΄Π΅-Π½ΠΈΠ±ΡΠ΄Ρ Π² ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ΅:
Task.Run(() => Run(i, cancelTokenSource.Token));
// ΠΠ°ΠΏΡΡΠΊ ΡΠΈΠ»ΠΎΡΠΎΡΠ°.
// ΠΠ»ΡΡΠ΅Π²ΠΎΠ΅ ΡΠ»ΠΎΠ²ΠΎ async -- ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡ ΡΡΠ°Π½ΡΠ»ΠΈΡΡΠ΅Ρ ΡΡΠΎΡ ΠΌΠ΅ΡΠΎΡ Π² Π°ΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΠΉ.
public async Task Run(int i, CancellationToken token)
{
while (true)
{
// await -- Π±ΡΠ΄Π΅ΠΌ ΠΎΠΆΠΈΠ΄Π°ΡΡ ΠΊΠ°ΠΊΠΎΠ³ΠΎ-ΡΠΎ ΡΠΎΠ±ΡΡΠΈΡ.
await TakeForks(i);
// ΠΠΎΡΠ»Π΅ await, ΠΏΡΠΎΠ΄ΠΎΠ»ΠΆΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π² Π΄ΡΡΠ³ΠΎΠΌ ΠΏΠΎΡΠΎΠΊΠ΅.
eatenFood[i] = (eatenFood[i] + 1) % (int.MaxValue - 1);
// ΠΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠΎΠ±ΡΡΠΈΠΉ Π΄Π»Ρ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ.
await PutForks(i);
Think(i);
if (token.IsCancellationRequested) break;
}
}
async Task TakeForks(int i)
{
bool hasForks = false;
while (!hasForks)
{
// ΠΠ·Π°ΠΈΠΌΠΎΠΈΡΠΊΠ»ΡΡΠ°ΡΡΠΈΠΉ Π΄ΠΎΡΡΡΠΏ ΠΊ ΡΡΠΎΠ»Ρ:
await _tableSemaphore.WaitAsync();
if (forks[Left(i)] == 0 && forks[Right(i)] == 0)
{
forks[Left(i)] = i+1;
forks[Right(i)] = i+1;
hasForks = true;
}
_tableSemaphore.Release();
// ΠΡΠ΄Π΅ΠΌ ΠΎΠΆΠΈΠ΄Π°ΡΡ, ΡΡΠΎΠ±Ρ ΡΠΎΡΠ΅Π΄ ΠΏΠΎΠ»ΠΎΠΆΠΈΠ» Π²ΠΈΠ»ΠΊΠΈ:
if (!hasForks)
await _philosopherSemaphores[i].WaitAsync();
}
}
// ΠΠ΄Π΅ΠΌ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ ΡΡΠΎΠ»Ρ ΠΈ ΠΊΠ»Π°Π΄Π΅ΠΌ Π²ΠΈΠ»ΠΊΠΈ.
async Task PutForks(int i)
{
await _tableSemaphore.WaitAsync();
forks[Left(i)] = 0;
// "ΠΡΠΎΠ±ΡΠ΄ΠΈΡΡ" ΡΠΎΡΠ΅Π΄Π΅ΠΉ, Π΅ΡΠ»ΠΈ ΠΎΠ½ΠΈ "ΡΠΏΠ°Π»ΠΈ".
_philosopherSemaphores[LeftPhilosopher(i)].Release();
forks[Right(i)] = 0;
_philosopherSemaphores[RightPhilosopher(i)].Release();
_tableSemaphore.Release();
}
Nzira ne async
/ await
inoshandurirwa muchina unonyengera wehurumende uyo pakarepo unodzorera mukati mawo Task
. Kuburikidza nayo, unogona kumirira kupedzwa kweiyo nzira, kuibvisa, uye nezvimwe zvese zvaungaite neTask. Mukati menzira, muchina wehurumende unodzora kuuraya. Chinokosha ndechokuti kana pasina kunonoka, ipapo kuurayiwa kunopindirana, uye kana iripo, ipapo tambo inosunungurwa. Kuti unzwisise zviri nani izvi, zviri nani kutarisa iyi muchina wehurumende. Iwe unogona kugadzira maketani kubva kune aya async
/ await
nzira.
Ngatiedze. Basa revazivi ve100 pamushini une 4 logic cores, 8 seconds. Mhinduro yapfuura neMonitor yakangomhanyisa tambo ina dzekutanga uye dzimwe dzese hadzina kumhanya zvachose. Imwe neimwe yeidzi shinda ina yaive isina basa kweinenge 4ms. Uye iyo async / yekumirira mhinduro yakamhanya ese zana, ine avhareji yekumirira ye4 masekonzi imwe neimwe. Ehe, mumasisitimu chaiwo, kusashanda kwemasekonzi matanhatu hakugamuchirwe uye zviri nani kusagadzirisa zvikumbiro zvakawanda seizvi. Mhinduro neMonitor yakazove isina scalable zvachose.
mhedziso
Sezvauri kuona kubva mumienzaniso midiki iyi, .NET inotsigira akawanda ma synchronization anovaka. Zvisinei, hazvisi pachena nguva dzose mashandisirwo azvo. Ndinovimba kuti chinyorwa ichi chakabatsira. Parizvino, uku ndiko kuguma, asi kuchine zvinhu zvakawanda zvinonakidza zvasara, semuenzaniso, kuunganidzwa-kwakachengeteka, TPL Dataflow, Reactive programming, Software Transaction model, nezvimwe.
Sources
- Kuyerera kwekuona:
Concurrency Visualizer - MSDN:
Kubata ,Asynchronous programming mapatani nevamwe vazhinji. dr. - [Richter] - CLR kuburikidza neC#, Jeffrey Richter
- [Eric Lippert] -
Nezve kukiya Purogiramu yekupa - Mufananidzo - "Dhani pakati peminondo", G. Semiradsky
Source: www.habr.com