logo

МНОГОПОТОЧНОСТ В C

Въведение:

В C терминът 'многопоточност' описва използването на множество нишки едновременно. Всяка нишка прави a различна задача . Поради едновременния характер на многонишковостта, много задачи могат да се изпълняват наведнъж. Освен това, многопоточност намалява на Използване на ресурси на процесора . Има две категории многозадачност: базирани на процеса и базирани на нишки . Когато нещо е описано като многопоточност, това означава, че поне две или може би повече нишки се изпълняват в един и същи процес едновременно. Първо трябва да разберем какво е нишка и процес, за да разберем многонишковостта в C. Нека разгледаме тези теми, за да разберем по-добре.

конвертирайте nfa в dfa

Какво представляват процесите и нишките?

А резба е фундаментална сграда блок на изпълнението на всеки процес. Програмата се състои от няколко процеса и всеки процес се състои от нишки, които са много по-основни единици. Следователно нишката може да се счита за основния градивен елемент на процес или за по-простата единица, която съвместно определя използването на процесора.

Следните елементи са включени в нишка:

ID на темата:

Това е специално ID на нишката който се генерира по време на формиране на нишка и се запазва за продължителността на тази конкретна нишка.

Програмен брояч:

Това е ценност, която хардуерни натоварвания .

Регистриран комплект:

Това е колекция от общи регистри .

Купчина:

Това е остатък от това конкретна нишка .

Освен това, ако две нишки работят едновременно в един и същ процес, те споделят код , секции с данни и други ресурси на операционната система като файл отваря и сигнали . Тежък процес, тип конвенционален процес, може да контролира една нишка. Въпреки това, многонишковият контрол има капацитета да отваря и изпълнява множество задачи едновременно. Системата става значително по-ефективна в резултат на използването на нишки, поради което те са полезни.

Разликата между единичен и многопоточност в C е обяснено. На първо място, това е а еднонишков процес . В резултат на това целият блок, включително код, данни, и т.н. - се разглежда като един процес и този процес има само една нишка. Това означава, че тази техника ще изпълнява само една задача наведнъж. Но има а многонишков процес което стои в опозиция на това. Има дейности като код, стек, данни , и файлове също, но те се изпълняват от няколко нишки, всяка от които има собствен стек и регистри. Като се има предвид, че множество задачи могат да бъдат изпълнени наведнъж в тази ситуация, процесът е известен като a многонишков процес .

Нишката се предлага в две разновидности:

Нишка на ниво потребител:

Това е на потребителско ниво, както подсказва името. Ядрото не получава достъп до своите данни.

Нишка на ниво ядро

Видът нишка се отнася до връзката на нишката с ядрото и операционната система на системата.

процес- Поредицата от стъпки, предприети за изпълнение на програма, може да се нарече процес . Една програма не се изпълнява незабавно, когато се стартира. Той е разделен на няколко основни стъпки, които се извършват последователно по организиран начин, за да доведат до изпълнението на даден процес в крайна сметка.

Процес, който е разделен на по-малки стъпки, се нарича a „клонинг или дъщерен процес“, докато оригиналният процес се нарича 'родителски' процес . В паметта всеки процес използва определено количество пространство, което не се споделя с други процеси.

Една процедура преминава през няколко етапа преди изпълнението.

какво е uri

НОВО-

В тази ситуация има нов процес генерирани .

ГОТОВ-

Когато даден процес е подготвен и чака за присвояване на процесор, той е в това състояние.

БЯГАНЕ-

Когато процесът е активен, това е състоянието.

ОЧАКВАНЕ-

Когато един процес е в това състояние, нещо е очакване случва се.

ПРЕКРАТЕН-

java util дата

Това е състоянието, в което се извършва процедурата.

Защо C е многонишков?

Многопоточност в идеята C може да се използва чрез паралелизъм за подобряване на an функционалност на приложението . Помислете за случая, когато имате няколко отворени раздела в прозорец на браузър. След това всеки раздел работи едновременно и може да се нарича a Нишка . Ако приемем, че използваме Microsoft Excel , една нишка ще управлява форматиране на текст , и една нишка ще обработка на входа . Следователно функцията за многопоточност на C улеснява изпълнението на множество задачи наведнъж. Създаването на нишка е значително по-бързо. Прехвърлянето на контекст между нишките става по-бързо. Освен това комуникацията между нишките може да се осъществи по-бързо и прекратяването на нишките е лесно.

Как се пишат C програми за многопоточност?

Въпреки че многонишковите приложения не са вградени в езика C, това е възможно в зависимост от операционната система. The стандартна библиотека threads.h се използва за реализиране на идеята за многопоточност в ° С . В момента обаче няма компилатор, който да може да направи това. Трябва да използваме специфични за платформата реализации, като например „POSIX“ библиотека с нишки, като използвате заглавния файл pthread.h , ако искаме да използваме многопоточност в C. 'Pthreads' е другото име за това. А POSIX Нишката може да бъде създадена по следните начини:

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

В такъв случай, Pthread_create създава нова нишка, за да направи нишката изпълнима. Позволява ви да внедрявате многопоточност в C толкова пъти, колкото желаете във вашия код. Параметрите и техните описания от по-рано са изброени тук.

тема:

Това е единична идентификация че подпроцесът се връща .

атрибут:

Когато искаме да зададем атрибути на нишка, използваме това непрозрачен атрибут .

стартова_рутина:

Кога стартова_рутина се генерира, нишката ще изпълни рутина.

аргумент:

Параметърът, който стартова_рутина получава. НУЛА ще се използва, ако не са дадени аргументи.

Някои примери за многопоточност на C

Ето някои примери за проблеми с многонишковостта в C.

1. Проблемът читател-писател

Често срещан проблем на операционната система при синхронизирането на процеси е проблем с четец/записвач . Да приемем, че имаме база данни, която Читатели и Писатели , две различни потребителски категории, имат достъп. Читатели са единствените, които могат Прочети базата данни, докато Писатели са единствените, които могат да четат базата данни и да я актуализират. Да използваме IRCTC като прост пример. Ако искаме да проверим състоянието на конкретен номер на влака , просто въведете номера на влака в системата, за да видите съответната информация за влака. Тук се показва само информацията, която присъства на уебсайта. Операторът за четене е това. Въпреки това, ако искаме да резервираме билет, трябва да попълним формуляра за резервация на билет с подробности като нашето име, възраст и т.н. Така че ще извършим операция за запис тук. Ще бъдат направени някои корекции на IRCTC база данни .

Проблемът е, че няколко души едновременно се опитват да получат достъп до IRCTC база данни . Те може да са а писател или а читател . Проблемът възниква, ако четец вече използва базата данни и писател има достъп до нея едновременно, за да работи върху едни и същи данни. Друг проблем възниква, когато писател използва база данни, а читател има достъп до същата информация като базата данни. Трето, има трудност, когато един писател актуализира базата данни, докато друг се опитва да актуализира данни в същата база данни. Четвъртият сценарий възниква, когато двама читатели се опитат да извлекат един и същ материал. Всички тези проблеми възникват, ако читателят и писателят използват едни и същи данни от базата данни.

Семафорът е метод, който се използва за решаване на този проблем. Нека да разгледаме илюстрация как да използваме този проблем.

Процес на четене:

 #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;>

Обяснение:

В този код имаме споделените променливи данни и брой читатели rc . The wrt състояние променлива се използва за ограничаване на достъпа за писателски процес , и мютекс се използва за гарантиране на взаимно изключване за достъп до споделените данни.

Процесът на четене е представен от функция reader(). . The брой читатели (rc) се увеличава преди да се постигне заключване на mutex . То използва pthread_cond_wait() да чакам на wrt състояние променлива, ако е първи читател (rc == 1) . В резултат на това писателите ще бъдат възпрепятствани да пишат, докато всички читатели не завършат.

Процесът на четене проверява дали това е последен читател (rc == 0) и сваля четеца брой (rc--) след прочитане на споделените данни. Ако беше, pthread_cond_signal() сигнализира за wrt състояние променлива, която позволява на процесите на чакащ запис да продължат.

Използвайки pthread_create() и pthread_join() функции , ние нов и присъединяване множество читателски теми в Главна функция . Индивидуален идентификатор се присвоява на всяка нишка на четец за идентифициране.

Процес на писане:

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

В горния пример, същото като читателски процес , се извършва операция, известна като операция на изчакване 'wrt' когато потребител желае да получи достъп до данните или обекта. След това новият потребител няма да има достъп до обекта. И след като потребителят приключи писането, се извършва друга операция за сигнал wrt .

2. проблем със заключването и отключването:

Идеята на а мютекс се използва при многопоточност в C, за да се гарантира, че няма да има a състезателно състояние между нишки . Когато множество нишки започнат да обработват едни и същи данни наведнъж, това обстоятелство е известно като състезание . Ако обаче съществуват тези обстоятелства, ние трябва. Ние използваме заключване на mutex() и unlock() функции за да защитите определена секция от код за конкретна нишка. Така че друга нишка не може да започне да изпълнява същата операция. The 'критична секция/регион' е името, дадено на тази защитена кодова област. Преди да използваме споделените ресурси, ние настройваме много в определена област и след като приключим с използването им, ги отключваме отново.

Нека разгледаме работата на mutex за заключване и отключване в многопоточност в C:

Пример:

 #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;>

Обяснение:

конвертиране на int в низ

В този пример по-горе обясняваме как ключалка и отключване определен регион от код, който ни предпазва от състезателната ситуация. 'pthread_mutex_t' се използва като инициализатор в горния пример. 'pthread_mutex_lock' е тогава написана преди началото на кода, който искаме да заключим. Кодирането, което искаме да заключим, е завършено след това. След това заключването на кода се прекратява с помощта на 'pthread_mutex_unlock' ; напред, нито един код няма да бъде в режим на заключване.

параметри по подразбиране на java

Проблемът с философа за хранене:

Един от класическите проблеми със синхронизацията е трапезария философ проблем . Изисква се просто разпределение на ресурси за няколко процеса, но не трябва да води до a патова ситуация или глад . The проблем с трапезния философ може да се разглежда като пряко представяне на редица процеси, всеки от които изисква ресурси. Тъй като всеки от тези процеси изисква разпределение на ресурси, е необходимо тези ресурси да се разпределят между всички процеси, така че никой процес да не блокира или да спре да работи.

Да приемем, че има петима философи, седнали в a маса с формата на кръг . В един момент ядат, а в друг размишляват за нещо. Около кръглата маса философите са разположени равномерно по столовете. Освен това в средата на масата има купа с ориз и пет клечки за всеки философ. Когато философът почувства, че не може да взаимодейства с колегите си, които седят наблизо.

Една философка от време на време взема две клечки, когато огладнее. Тя избира две клечки от съседите си - една върху нея наляво и един върху нея точно - които са лесно достъпни. Но философът никога не трябва да взема повече от една клечка наведнъж. Тя очевидно няма да може да вземе клечката, която съседът използва.

Пример:

Нека използваме пример, за да демонстрираме как това се прилага в 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;>

Обяснение:

Клечки може да се представи със семафор. Тъй като има клечки на масата и нито един философ не е избрал такъв, всички компоненти на клечките първо се инициализират на 1 . Сега какво клечка[i] е избран за първи клечка за хранене. клечка[i] и пръчица[(i+1)%5] подлежат на първата операция на изчакване. Тези операция за изчакване на пръчици показва, че философът ги е подхванал. Процесът на хранене започва, след като философът избере своя клечка за хранене . Сигналната операция вече се извършва на пръчици за хранене [i] и [(i+1)%5] след като философът приключи с яденето. След това философът отново заспива.

За да се определи дали поднишка се е присъединил към основната нишка или не, използвахме pthread_join функция . По подобен начин проверихме дали мютекс заключване е инициализирано с помощта на pthread_mutex_init метод.

За да инициализираме и проверим дали новата нишка е създадена или не, ние използвахме pthread_create функция . Подобно на това ние унищожихме заключване на mutex използвайки pthread_mutex_destroy функция.

Проблемът производител-потребител:

Често срещан проблем при синхронизирането на многопоточни процеси е проблем производител-потребител . В него присъстват два процеса: първият е процес на производителя , а втората е процес на потребителя . Освен това се предполага, че и двете операции се извършват едновременно и паралелно. Освен това те са процес на сътрудничество, което предполага, че споделят нещо един с друг. Важно е, когато буферът е пълен , производителят не може да добавя данни. Когато буферът е празен, потребителят не може да извлича данни от буфера, тъй като общият размер на буфера между производителя и потребителя е фиксирани . Въпросът е формулиран по този начин. Следователно, за да приложим проблема Производител-Потребител и да го разрешим, ще използваме идеята за паралелно програмиране.

Пример:

 #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); } 

Изход:

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

Обяснение:

Изпълняваме две задачи. Функциите консуматор() и продуцент() посочете състоянието и работата на консуматор и продуцент . The метод producer(). ще създаде заключване на mutex и определете дали буферът е пълен когато се нарича. Когато буферът е пълен, няма да се произвежда нищо. Ако не, ще стане създавам , а след това, след производство , ще се заспи, за да отключи заключване на mutex . Подобно на продуцент , потребителят първо създава заключване на mutex , проверява буфер , консумира на продукт , и след това освобождава ключалката, преди да заспи отново.

А брояч (x) ще се използва по време на производството и ще продължи да расте, докато производителят не произведе артикула. Потребителят обаче ще произвежда по-малко от същото произведено елемент (x) .

Заключение:

Идеята за използване две или повече нишки за изпълнение на програма е известно като многопоточност на езика за програмиране C. Многопоточност дава възможност за едновременно изпълнение на няколко задачи. Най-простият изпълним компонент на програма е a резба . Процесът е идеята, че дадена задача може да бъде изпълнена, като се раздели на няколко по-малки подпроцеси .

Заглавният файл pthread.h се изисква, за да се приложи многопоточност в C, тъй като не може да се направи директно.