logo

VEČNITNOST V C

Uvod:

V C je izraz 'večnitnost' opisuje uporabo številnih niti sočasno. Vsaka nit naredi a drugačna naloga . Zaradi sočasne narave večnitnosti se lahko naenkrat izvede več nalog. Poleg tega večnitnost zmanjšuje Poraba virov procesorja . Obstajata dve kategoriji večopravilnosti: temelji na procesu in na osnovi niti . Ko je karkoli opisano kot večnitnost, to pomeni, da se vsaj dve ali morda več niti izvajata v istem procesu hkrati. Najprej moramo razumeti, kaj sta nit in proces, da lahko razumemo večnitnost v C. Oglejmo si te teme, da bomo bolje razumeli.

java binarno drevo

Kaj so procesi in niti?

A nit ali je temeljna zgradba blok izvajanja katerega koli postopka. Program je sestavljen iz več procesov, vsak proces pa je sestavljen iz niti, ki so veliko bolj osnovne enote. Zato lahko nit štejemo za temeljni gradnik procesa ali enostavnejšo enoto, ki skupaj določa izkoriščenost procesorja.

V nit so vključeni naslednji elementi:

ID niti:

Je posebna ID niti ki je ustvarjen v času oblikovanja niti in ohranjen za določeno trajanje niti.

Programski števec:

Je vrednota, ki jo obremenitve strojne opreme .

Registriran komplet:

Je zbirka skupni registri .

Kup:

To je ostanek tega določena nit .

Poleg tega, če dve niti delujeta hkrati v istem procesu, si delita Koda , razdelki podatkov , in drugi viri operacijskega sistema, kot je datoteka odpre in signali . Težki proces, vrsta običajnega procesa, lahko nadzoruje eno nit. Vendar ima večnitnost nadzora zmožnost odpiranja in izvajanja več nalog hkrati. Sistem postane zaradi uporabe niti bistveno bolj učinkovit, zato so uporabne.

Razlika med samski in večnitnost v C je razloženo. Najprej je a enonitni proces . Posledično celoten blok, vključno z koda, podatki, itd.-se obravnava kot en proces in ta proces ima samo eno nit. To pomeni, da bo ta tehnika opravila samo eno nalogo naenkrat. Vendar obstaja a večnitnega postopka ki stoji v nasprotju s tem. Obstajajo dejavnosti, kot so koda, sklad, podatki , in datoteke prav tako, vendar jih izvaja več niti, od katerih ima vsaka svoj sklad in registre. Glede na to, da je v tej situaciji mogoče naenkrat dokončati številne naloge, je postopek znan kot a večnitnega postopka .

Nit je na voljo v dveh različicah:

Nit na ravni uporabnika:

Je na ravni uporabnika, kot pove že ime. Jedro nima dostopa do svojih podatkov.

Nit na ravni jedra

Vrsta niti se nanaša na odnos niti do jedra in operacijskega sistema sistema.

Proces- Niz korakov, izvedenih za izvedbo programa, lahko imenujemo postopek . Program se ne izvede takoj, ko se zažene. Razdeljen je na nekaj osnovnih korakov, ki se organizirano izvajajo zaporedoma, da na koncu vodijo do izvedbe procesa.

Postopek, ki je bil razdeljen na manjše korake, se imenuje a 'klon ali podrejeni proces', medtem ko se prvotni postopek imenuje 'nadrejeni' proces . V pomnilniku vsak proces uporablja določeno količino prostora, ki ni v skupni rabi z drugimi procesi.

Postopek gre skozi nekaj stopenj pred izvedbo.

NOVO-

V tej situaciji je nov proces ustvarjena .

PRIPRAVLJEN-

Ko je proces pripravljen in čaka na dodelitev procesorja, je v tem stanju.

js večvrstični niz

TEČE -

Ko je proces aktiven, je stanje.

ČAKANJE-

Ko je proces v tem stanju, nekaj je čakanje zgoditi se.

KONČANO-

To je stanje, v katerem se postopek izvaja.

Zakaj je C večniten?

Večnitnost v ideji C je mogoče izkoristiti vzporednost za izboljšanje an funkcionalnost aplikacije . Razmislite o primeru, ko imate v oknu brskalnika odprtih več zavihkov. Nato vsak zavihek deluje sočasno in se lahko imenuje a nit . Ob predpostavki, da uporabljamo Microsoft Excel , bo upravljala ena nit oblikovanje besedila , in ena nit bo obravnavati vnos . Zato funkcija večnitnosti C-ja omogoča preprosto izvajanje več nalog hkrati. Izdelava niti je bistveno hitrejša. Prenos konteksta med nitmi se zgodi hitreje. Poleg tega je lahko komunikacija med nitmi hitrejša, zaključek niti pa je preprost.

Kako napisati programe C za večnitnost?

Čeprav aplikacije za večnitnost niso vgrajene v jezik C, je to mogoče, odvisno od operacijskega sistema. The standardna knjižnica threads.h se uporablja za implementacijo ideje večnitnosti v C . Vendar trenutno ni nobenega prevajalnika, ki bi to zmogel. Uporabiti moramo izvedbe, specifične za platformo, kot je 'POSIX' knjižnica niti, z uporabo datoteke glave pthread.h , če želimo uporabiti večnitnost v C. 'Pthreads' je drugo ime za to. A POSIX nit lahko ustvarite na naslednje načine:

 #include pthread_create (thread, attr, start_routine, arg) 

V tem primeru, Pthread_create ustvari novo nit, da naredi nit izvršljivo. Omogoča vam, da v kodi implementirate večnitnost v C tolikokrat, kot želite. Tukaj so navedeni parametri in njihovi opisi od prej.

nit:

Je enkratna identifikacija da vrne podproces .

attr:

Ko želimo nastaviti atribute niti, uporabimo to neprozoren atribut .

java je enaka

začetek_rutine:

Kdaj start_rutine se ustvari, bo nit izvajala rutino.

arg:

Parameter, ki ga start_rutine prejme. NIČ bo uporabljeno, če ne boste podali nobenih argumentov.

Nekateri primeri večnitnosti C

Tukaj je nekaj primerov težav z večnitnostjo v C.

1. Vprašanje bralec-pisec

Pogosta težava operacijskega sistema pri sinhronizaciji procesov je problem bralnika/pisovalca . Predpostavimo, da imamo bazo podatkov Bralci in Pisatelji , dve različni kategoriji uporabnikov, lahko dostopajo. Bralci so edini, ki lahko prebrati baze podatkov, medtem ko Pisatelji so edini, ki lahko berejo bazo podatkov in jo tudi posodabljajo. Uporabimo IRCTC kot preprost primer. Če želimo preveriti stanje določenega številka vlaka , preprosto vnesite številko vlaka v sistem, da si ogledate ustrezne informacije o vlaku. Tukaj so prikazane samo informacije, ki so prisotne na spletnem mestu. Operator branja je to. Vendar, če želimo rezervirati vstopnico, moramo izpolniti obrazec za rezervacijo vstopnice s podatki, kot so naše ime, starost itd. Torej, tukaj bomo izvedli operacijo pisanja. Nekaj ​​prilagoditev bo Baza podatkov IRCTC .

Težava je v tem, da več ljudi hkrati poskuša dostopati do Baza podatkov IRCTC . Morda so a pisatelj ali a bralec . Težava se pojavi, če bralec že uporablja bazo podatkov in pisec hkrati dostopa do nje, da dela na istih podatkih. Druga težava se pojavi, ko pisec uporablja zbirko podatkov, bralec pa dostopa do istih informacij kot v zbirki podatkov. Tretjič, obstaja težava, ko en pisec posodobi bazo podatkov, medtem ko drugi poskuša posodobiti podatke v isti bazi podatkov. Četrti scenarij se zgodi, ko dva bralca poskušata pridobiti isto gradivo. Vsa ta vprašanja se pojavijo, če bralec in pisec uporabljata iste podatke baze podatkov.

Semafor je metoda, ki se uporablja za rešitev te težave. Oglejmo si ilustracijo, kako uporabiti to težavo.

Postopek bralnika:

 #include #include #include int rc = 0; // Reader count int data = 0; // Shared data pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_twrt = PTHREAD_COND_INITIALIZER; void* reader(void* arg) { int reader_id = *(int*)arg; pthread_mutex_lock(&mutex); rc++; if (rc == 1) pthread_cond_wait(&wrt, &mutex); pthread_mutex_unlock(&mutex); // Reading the shared data printf('Reader %d reads data: %d
&apos;, reader_id, data); pthread_mutex_lock(&amp;mutex); rc--; if (rc == 0) pthread_cond_signal(&amp;wrt); pthread_mutex_unlock(&amp;mutex); return NULL; } int main() { pthread_treaders[5]; // Assuming 5 reader threads int reader_ids[5]; for (int i = 0; i<5; i++) { reader_ids[i]="i" + 1; pthread_create(&readers[i], null, reader, &reader_ids[i]); } joining reader threads for (int i="0;" i< 5; pthread_join(readers[i], null); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Reader 1 reads data: 0 Reader 2 reads data: 0 Reader 3 reads data: 0 Reader 4 reads data: 0 Reader 5 reads data: 0 </pre> <p> <strong>Explanation:</strong> </p> <p>In this code, we have the shared variable data and the <strong> <em>reader count rc</em> </strong> . The <strong> <em>wrt condition</em> </strong> variable is used to limit access for the <strong> <em>writer process</em> </strong> , and the <strong> <em>mutex</em> </strong> is used to guarantee mutual exclusion for accessing the shared data.</p> <p>The reader process is represented by the <strong> <em>reader() function</em> </strong> . The <strong> <em>reader count (rc)</em> </strong> is increased before attaining the <strong> <em>mutex lock</em> </strong> . It uses <strong> <em>pthread_cond_wait()</em> </strong> to wait on the <strong> <em>wrt condition</em> </strong> variable if it is the <strong> <em>first reader (rc == 1)</em> </strong> . As a result, writers will be prevented from writing until all readers have completed.</p> <p>The reader process checks if it was the <strong> <em>last reader (rc == 0)</em> </strong> and lowers the reader <strong> <em>count (rc--)</em> </strong> after reading the shared data. If it was, <strong> <em>pthread_cond_signal()</em> </strong> signals the <strong> <em>wrt condition</em> </strong> variable to let waiting writer processes continue.</p> <p>Using the <strong> <em>pthread_create()</em> </strong> and <strong> <em>pthread_join() functions</em> </strong> , we <strong> <em>new</em> </strong> and <strong> <em>join</em> </strong> multiple reader threads in the <strong> <em>main() function</em> </strong> . An individual ID is assigned to each reader thread for identifying purposes.</p> <h3>Writer process:</h3> <pre> wait(wrt); . . WRITE INTO THE OBJECT . signal(wrt); </pre> <p>In the above example, same as the <strong> <em>reader process</em> </strong> , an operation known as the wait operation is carried out on <strong> <em>&apos;wrt&apos;</em> </strong> when a user wishes to access the data or object. After that, the new user won&apos;t be able to access the object. And once the user has finished writing, another signal operation is performed on <strong> <em>wrt</em> </strong> .</p> <h3>2. lock and unlock problem:</h3> <p>The idea of a <strong> <em>mutex</em> </strong> is utilized in multithreading in C to guarantee that there won&apos;t be a <strong> <em>race condition</em> </strong> between the <strong> <em>threads</em> </strong> . When multiple threads begin processing the same data at once, this circumstance is known as <strong> <em>racing</em> </strong> . However, if these circumstances exist, we must. We use the <strong> <em>mutex&apos;s lock()</em> </strong> and <strong> <em>unlock() functions</em> </strong> to secure a particular section of code for a specific thread. Such that, another thread cannot begin performing the same operation. The <strong> <em>&apos;critical section/region&apos;</em> </strong> is the name given to this protected code area. Before using the shared resources, we set up a lot in a certain area, and once we&apos;ve finished using them, we unlock them once more.</p> <p>Let&apos;s examine the operation of the mutex for locking and unlocking in multithreading in C:</p> <p> <strong>Example:</strong> </p> <pre> #include #include #include pthread_mutex_tmy_mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void *thread_function(void *arg) { pthread_mutex_lock(&amp;my_mutex); shared_data++; // Modify the shared data printf(&apos;Thread %ld: Shared data modified. New value: %d
&apos;, (long)arg, shared_data); pthread_mutex_unlock(&amp;my_mutex); return NULL; } int main() { pthread_tthreads[5]; // Assuming 5 threads for (int i = 0; i<5; i++) { if (pthread_create(&threads[i], null, thread_function, (void *)(long)(i + 1)) !="0)" fprintf(stderr, 'error creating thread %d
', i 1); return 1; } for (int i< 5; (pthread_join(threads[i], null) joining 0; < pre> <p> <strong>Output:</strong> </p> <pre> Thread 1: Shared data modified. New value: 1 Thread 2: Shared data modified. New value: 2 Thread 3: Shared data modified. New value: 3 Thread 4: Shared data modified. New value: 4 Thread 5: Shared data modified. New value: 5 </pre> <p> <strong>Explanation:</strong> </p> <p>In this above example, we explain how we <strong> <em>lock</em> </strong> and <strong> <em>unlock</em> </strong> a certain region of code that shields us from the racing situation. <strong> <em>&apos;pthread_mutex_t&apos;</em> </strong> is used as an <strong> <em>initializer</em> </strong> in the example above. <strong> <em>&apos;pthread_mutex_lock&apos;</em> </strong> is then <strong> <em>written</em> </strong> before the beginning of the code that we want to lock. The coding that we wish to lock is finished after that. After that, the locking of the code is terminated using <strong> <em>&apos;pthread_mutex_unlock&apos;</em> </strong> ; going forward, no code will be in lock mode.</p> <h2>The Dining Philosopher Problem:</h2> <p>One of the classic issues with synchronization is the <strong> <em>dining philosopher issue</em> </strong> . Simple resource allocation for several processes is required but shouldn&apos;t result in a <strong> <em>stalemate</em> </strong> or <strong> <em>hunger</em> </strong> . The <strong> <em>dining philosopher problem</em> </strong> can be viewed as a straightforward representation of a number of processes, each of which is demanding resources. Since each of these processes requires a resource allocation, it is necessary to distribute those resources across all of the processes so that no one process ever gets stuck or stops working.</p> <p>Assume there are five philosophers seated at a <strong> <em>circle-shaped table</em> </strong> . They eat at one point and ponder about something at another. Around the round table, the philosophers are evenly spaced out on the chairs. Additionally, there is a bowl of rice and five chopsticks for each philosopher in the middle of the table. When the philosopher feels she cannot interact with her colleagues who are seated nearby.</p> <p>A philosopher occasionally takes up two chopsticks when she becomes hungry. She chooses two chopsticks from her neighbors-one on her <strong> <em>left</em> </strong> and one on her <strong> <em>right</em> </strong> -that are within easy reach. But the philosopher should never pick up more than one chopstick at once. She will obviously be unable to pick up the chopstick that the neighbor is using.</p> <p> <strong>Example:</strong> </p> <p>Let&apos;s use an example to demonstrate how this is implemented in C.</p> <pre> #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf('failed to initialize the mutex
'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf('error in thread creation.
'); &message); join thread.
'); printf('mutex destroyed.
'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;></pre></5;></pre></5;>

Pojasnilo:

V tej kodi imamo podatke spremenljivke v skupni rabi in število bralcev rc . The wrt stanje spremenljivka se uporablja za omejitev dostopa za pisateljski proces , in mutex se uporablja za zagotavljanje medsebojne izključitve za dostop do skupnih podatkov.

Proces branja predstavlja reader() funkcijo . The število bralcev (rc) se poveča, preden doseže zaklepanje mutexa . Uporablja se pthread_cond_wait() počakati na wrt stanje spremenljivka, če je prvi bralec (rc == 1) . Zato pisci ne bodo mogli pisati, dokler vsi bralci ne dokončajo.

Postopek bralnika preveri, ali je bil zadnji bralec (rc == 0) in spusti čitalnik štetje (rc--) po branju skupnih podatkov. če bi bilo, pthread_cond_signal() signalizira wrt stanje spremenljivka, ki omogoča nadaljevanje čakajočih zapisovalnih procesov.

Uporabljati pthread_create() in funkcije pthread_join(). , mi novo in pridruži se več niti bralcev v funkcija main(). . Posamezen ID je dodeljen vsaki niti bralnika za namene identifikacije.

Postopek pisca:

 wait(wrt); . . WRITE INTO THE OBJECT . signal(wrt); 

V zgornjem primeru enako kot pri bralni proces , se izvede operacija, znana kot operacija čakanja 'wrt' ko uporabnik želi dostopati do podatkov ali predmeta. Po tem novi uporabnik ne bo mogel dostopati do predmeta. In ko uporabnik konča pisanje, se izvede druga operacija signala wrt .

2. težava z zaklepanjem in odklepanjem:

Ideja a mutex se uporablja pri večnitnosti v C, da se zagotovi, da ne bo prišlo do a stanje dirke med niti . Ko več niti začne obdelovati iste podatke hkrati, je ta okoliščina znana kot dirkanje . Vendar, če te okoliščine obstajajo, moramo. Uporabljamo zaklepanje mutexa() in funkcije unlock(). da zavarujete določen del kode za določeno nit. Tako, da druga nit ne more začeti izvajati iste operacije. The 'kritični del/regija' je ime za to območje zaščitene kode. Pred uporabo skupnih virov na določenem območju nastavimo veliko, po končani uporabi pa jih še enkrat odklenemo.

Oglejmo si delovanje muteksa za zaklepanje in odklepanje v večnitnosti v C:

primer:

 #include #include #include pthread_mutex_tmy_mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void *thread_function(void *arg) { pthread_mutex_lock(&amp;my_mutex); shared_data++; // Modify the shared data printf(&apos;Thread %ld: Shared data modified. New value: %d
&apos;, (long)arg, shared_data); pthread_mutex_unlock(&amp;my_mutex); return NULL; } int main() { pthread_tthreads[5]; // Assuming 5 threads for (int i = 0; i<5; i++) { if (pthread_create(&threads[i], null, thread_function, (void *)(long)(i + 1)) !="0)" fprintf(stderr, \'error creating thread %d
\', i 1); return 1; } for (int i< 5; (pthread_join(threads[i], null) joining 0; < pre> <p> <strong>Output:</strong> </p> <pre> Thread 1: Shared data modified. New value: 1 Thread 2: Shared data modified. New value: 2 Thread 3: Shared data modified. New value: 3 Thread 4: Shared data modified. New value: 4 Thread 5: Shared data modified. New value: 5 </pre> <p> <strong>Explanation:</strong> </p> <p>In this above example, we explain how we <strong> <em>lock</em> </strong> and <strong> <em>unlock</em> </strong> a certain region of code that shields us from the racing situation. <strong> <em>&apos;pthread_mutex_t&apos;</em> </strong> is used as an <strong> <em>initializer</em> </strong> in the example above. <strong> <em>&apos;pthread_mutex_lock&apos;</em> </strong> is then <strong> <em>written</em> </strong> before the beginning of the code that we want to lock. The coding that we wish to lock is finished after that. After that, the locking of the code is terminated using <strong> <em>&apos;pthread_mutex_unlock&apos;</em> </strong> ; going forward, no code will be in lock mode.</p> <h2>The Dining Philosopher Problem:</h2> <p>One of the classic issues with synchronization is the <strong> <em>dining philosopher issue</em> </strong> . Simple resource allocation for several processes is required but shouldn&apos;t result in a <strong> <em>stalemate</em> </strong> or <strong> <em>hunger</em> </strong> . The <strong> <em>dining philosopher problem</em> </strong> can be viewed as a straightforward representation of a number of processes, each of which is demanding resources. Since each of these processes requires a resource allocation, it is necessary to distribute those resources across all of the processes so that no one process ever gets stuck or stops working.</p> <p>Assume there are five philosophers seated at a <strong> <em>circle-shaped table</em> </strong> . They eat at one point and ponder about something at another. Around the round table, the philosophers are evenly spaced out on the chairs. Additionally, there is a bowl of rice and five chopsticks for each philosopher in the middle of the table. When the philosopher feels she cannot interact with her colleagues who are seated nearby.</p> <p>A philosopher occasionally takes up two chopsticks when she becomes hungry. She chooses two chopsticks from her neighbors-one on her <strong> <em>left</em> </strong> and one on her <strong> <em>right</em> </strong> -that are within easy reach. But the philosopher should never pick up more than one chopstick at once. She will obviously be unable to pick up the chopstick that the neighbor is using.</p> <p> <strong>Example:</strong> </p> <p>Let&apos;s use an example to demonstrate how this is implemented in C.</p> <pre> #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf(\'failed to initialize the mutex
\'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf(\'error in thread creation.
\'); &message); join thread.
\'); printf(\'mutex destroyed.
\'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;></pre></5;>

Pojasnilo:

kako najti velikost monitorja

V tem zgornjem primeru pojasnjujemo, kako smo zaklepanje in odkleniti določeno področje kode, ki nas ščiti pred dirkalno situacijo. 'pthread_mutex_t' se uporablja kot inicializator v zgornjem primeru. 'pthread_mutex_lock' je potem napisano pred začetkom kode, ki jo želimo zakleniti. Kodiranje, ki ga želimo zakleniti, je po tem končano. Po tem se zaklepanje kode prekine z uporabo 'pthread_mutex_unlock' ; naprej nobena koda ne bo v načinu zaklepanja.

Problem filozofa obedovanja:

Ena od klasičnih težav s sinhronizacijo je vprašanje jedilnega filozofa . Potrebna je preprosta dodelitev virov za več procesov, vendar ne bi smela povzročiti a zastoj oz lakota . The jedilni filozofski problem lahko gledamo kot neposredno predstavitev številnih procesov, od katerih vsak zahteva vire. Ker vsak od teh procesov zahteva dodelitev virov, je treba te vire porazdeliti med vse procese, tako da se noben proces nikoli ne zatakne ali preneha delovati.

Predpostavimo, da pet filozofov sedi na a mizo v obliki kroga . V enem trenutku jedo, v drugem pa o nečem razmišljajo. Okoli okrogle mize so na stolih enakomerno razporejeni filozofi. Poleg tega je na sredini mize skleda riža in pet palčk za vsakega filozofa. Ko filozofinja čuti, da ne more komunicirati s svojimi kolegi, ki sedijo v bližini.

Filozof občasno vzame v roke dve palčki, ko postane lačna. Od sosedov izbere dve palčki - eno na sebi levo in ena na njej prav - ki so na dosegu roke. Toda filozof nikoli ne bi smel vzeti v roke več kot ene palčke hkrati. Očitno ne bo mogla pobrati palčke, ki jo uporablja sosed.

primer:

algoritmi binarnega iskanja

Uporabimo primer, da pokažemo, kako je to implementirano v C.

 #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf(\'failed to initialize the mutex
\'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf(\'error in thread creation.
\'); &message); join thread.
\'); printf(\'mutex destroyed.
\'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;>

Pojasnilo:

Palčke lahko predstavimo s semaforjem. Ker obstajajo palčke na mizi in noben filozof ni izbral enega, se vse komponente palčk najprej inicializirajo na 1 . Zdaj ko palčka[i] je bil izbran za prvega palčka. palčka[i] in palčka[(i+1)%5] so predmet prve operacije čakanja. te čakanje na palčke kaže, da jih je filozof pobral. Proces prehranjevanja se začne, ko si filozof izbere svojega palčka . Operacija signala se zdaj izvaja na jedilne palčke [i] in [(i+1)%5] ko je filozof končal z jedjo. Filozof nato spet zaspi.

Da bi ugotovili, ali je podnit se je pridružil glavni niti ali ne, uporabili smo funkcija pthread_join . Podobno smo preverili, ali je mutex zaklepanje je bilo inicializirano z uporabo pthread_mutex_init metoda.

Za inicializacijo in preverjanje, ali je bila nova nit ustvarjena ali ne, smo uporabili pthread_create funkcijo . Podobno kot smo uničili zaklepanje mutexa uporabljati pthread_mutex_destroy funkcijo.

Problem proizvajalec-potrošnik:

Pogosta težava pri sinhronizaciji večnitnega procesa je problem proizvajalec-potrošnik . V njej sta prisotna dva procesa: prvi je proizvajalčev proces , in drugi je potrošnikov proces . Poleg tega se predpostavlja, da se obe operaciji izvajata sočasno in vzporedno. Poleg tega so proces sodelovanja, kar pomeni, da si nekaj delijo drug z drugim. Pomembno je, da ko je medpomnilnik poln , proizvajalec ne more dodati podatkov. Ko je medpomnilnik prazen, potrošnik ne more izvleči podatkov iz medpomnilnika, ker je skupna velikost medpomnilnika med proizvajalcem in potrošnikom fiksno . Zadeva je izražena na ta način. Zato bomo za implementacijo in rešitev problema proizvajalec-potrošnik uporabili idejo vzporednega programiranja.

primer:

 #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } 

Izhod:

 1. producer 2. consumer 3. for exit Please enter your choice: 

Pojasnilo:

Opravljamo dve nalogi. Funkcije potrošnik() in producent() prikazuje stanje in delovanje potrošnik in producent . The metoda proizvajalca(). bo ustvaril zaklepanje mutexa in ugotovite, ali je medpomnilnik poln ko se imenuje. Ko je medpomnilnik poln, ne bo nič proizvedeno. Če ne, bo ustvariti , nato pa po proizvodnja , se bo preklopil v stanje spanja, da odklene zaklepanje mutexa . Kot producent , potrošnik najprej ustvari zaklepanje mutexa , preveri medpomnilnik , porabi izdelek , nato pa sprosti ključavnico, preden se vrne v spanec.

A števec (x) se bo uporabljal med proizvodnjo in bo še naprej rasel, dokler proizvajalec izdelka ne proizvede. Vendar bo potrošnik proizvedel manj istega predmet (x) .

Zaključek:

Ideja uporabe dva oz več niti za izvajanje programa je znan kot večnitnost v programskem jeziku C. Večnitnost omogoča hkratno izvajanje več nalog. Najenostavnejša izvršljiva komponenta programa je a nit . Proces je ideja, da je nalogo mogoče dokončati tako, da jo razdelimo na več manjših podprocesi .

Datoteka glave pthread.h je potreben za implementacijo večnitnosti v C, ker tega ni mogoče izvesti neposredno.