logo

MULTITHREADING EN C

Introduction:

En C, le terme 'multithreading' décrit l'utilisation de nombreux fils de discussion en même temps. Chaque fil fait un tâche différente . En raison de la nature concurrente du multithreading, de nombreuses tâches peuvent être exécutées en même temps. En plus, multithreading réduit le Utilisation des ressources du processeur . Il existe deux catégories de multitâches : basé sur des processus et basé sur des threads . Lorsque quelque chose est décrit comme multithreading, cela signifie qu'au moins deux threads, voire plus, s'exécutent simultanément dans le même processus. Nous devons d'abord comprendre ce que sont un thread et un processus afin d'appréhender le multithreading en C. Examinons ces sujets pour mieux comprendre.

création de liste en java

Que sont les processus et les threads ?

UN fil est le bâtiment fondamental bloc de l'exécution de tout processus. Un programme est composé de plusieurs processus, et chaque processus est constitué de threads, qui sont des unités beaucoup plus basiques. Par conséquent, le thread peut être considéré comme l’élément fondamental d’un processus ou comme l’unité plus simple qui détermine conjointement l’utilisation du processeur.

Les éléments suivants sont inclus dans un fil de discussion :

ID du sujet :

C'est un spécial identifiant du fil de discussion qui est généré au moment de la formation du thread et conservé pendant la durée de ce thread spécifique.

Compteur de programme:

C'est une valeur que le charges matérielles .

Un ensemble enregistré :

C'est une collection de registres communs .

Une pile:

C'est un vestige de ça fil spécifique .

De plus, si deux threads travaillent simultanément dans le même processus, ils partagent code , sections de données , et d'autres ressources du système d'exploitation telles que le fichier ouvre et signaux . Un processus lourd, un type de processus conventionnel, peut contrôler un thread. Cependant, un contrôle multithread a la capacité d’ouvrir et d’exécuter plusieurs tâches simultanément. Le système devient considérablement plus efficace grâce à l'utilisation de threads, c'est pourquoi ils sont utiles.

La distinction entre célibataire et multithreading en C est expliqué. Tout d'abord, c'est un processus monothread . En conséquence, l'ensemble du bloc, y compris le code, données, etc. - est considéré comme un seul processus, et ce processus n'a qu'un seul thread. Cela signifie que cette technique n'effectuera qu'une seule tâche à la fois. Mais il y a un processus multithread qui s'oppose à cela. Il y a des activités comme code, pile, données , et des dossiers également, mais ils sont exécutés par plusieurs threads, chacun possédant sa propre pile et ses propres registres. Étant donné que de nombreuses tâches peuvent être accomplies en même temps dans cette situation, le processus est appelé processus multithread .

Le fil est disponible en deux variétés :

Sujet au niveau de l'utilisateur :

C'est au niveau de l'utilisateur, comme son nom l'indique. Le noyau n'a pas accès à ses données.

Thread au niveau du noyau

Le type de thread fait référence à la relation du thread avec le noyau et le système d'exploitation du système.

Processus- La série d'étapes prises pour exécuter un programme peut être appelée processus . Un programme n'est pas immédiatement exécuté lorsqu'il est exécuté. Il se décompose en quelques étapes de base qui sont réalisées séquentiellement de manière organisée pour aboutir éventuellement à l'exécution d'un processus.

les meilleures voitures du monde

Un processus divisé en étapes plus petites est appelé 'processus clone ou enfant', tandis que le processus original est appelé le processus « parent » . Dans la mémoire, chaque processus utilise une certaine quantité d'espace qui n'est partagée avec aucun autre processus.

Une procédure passe par certaines étapes avant son exécution.

NOUVEAU-

Dans cette situation, un nouveau processus est généré .

PRÊT-

Lorsqu'un processus est préparé et attend qu'un processeur lui soit attribué, il se trouve dans cet état.

EN COURS D'EXÉCUTION-

Lorsque le processus est actif, c’est l’État.

EN ATTENDANT-

Lorsqu'un processus est dans cet état, quelque chose se passe en attendant se passer.

TERMINÉ-

C'est l'état dans lequel se déroule la procédure.

Pourquoi le C est-il multithread ?

Multithreading dans l'idée C peut être exploitée grâce au parallélisme pour améliorer une fonctionnalité de l'application . Prenons le cas où plusieurs onglets sont ouverts dans une fenêtre de navigateur. Ensuite, chaque onglet fonctionne simultanément et peut être appelé un Fil . En supposant que nous utilisons Microsoft Excel , un thread gérera formatage du texte , et un fil le fera gérer la saisie . Par conséquent, la fonctionnalité multithreading de C simplifie l’exécution de plusieurs tâches à la fois. La création d'un fil de discussion est considérablement plus rapide. Le transfert de contexte entre les threads se produit plus rapidement. De plus, la communication entre les threads peut être établie plus rapidement et la terminaison des threads est simple.

Comment écrire des programmes C pour le multithreading ?

Bien que les applications multithreading ne soient pas intégrées au langage C, cela est possible en fonction du système d'exploitation. Le bibliothèque standard threads.h est utilisé pour implémenter l'idée du multithreading dans C . Cependant, il n’existe actuellement aucun compilateur capable de faire cela. Nous devons utiliser des implémentations spécifiques à la plate-forme, telles que 'POSIX' bibliothèque de threads, en utilisant le fichier d'en-tête pthread.h , si nous voulons utiliser le multithreading en C. 'Pthreads' est un autre nom pour cela. UN POIX le fil de discussion peut être créé des manières suivantes :

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

Dans ce cas, Pthread_créer crée un nouveau thread afin de rendre le thread exécutable. Il vous permet d'implémenter le multithreading en C autant de fois que vous le souhaitez dans votre code. Les paramètres et leurs descriptions précédentes sont répertoriés ici.

fil de discussion:

C'est un identification singulière que le retours du sous-processus .

attribut :

Lorsque nous voulons définir les attributs du thread, nous utilisons ceci attribut opaque .

start_routine :

Quand start_routine est généré, le thread exécutera une routine.

bande de base vs haut débit

argument :

Le paramètre que le start_routine reçoit. NUL sera utilisé si aucun argument n’est donné.

Certains exemples de multithreading C

Voici quelques exemples de problèmes de multithreading en C.

1. La question du lecteur-écrivain

Un problème courant du système d'exploitation avec la synchronisation des processus est le problème de lecteur/écrivain . Supposons que nous ayons une base de données qui Lecteurs et Écrivains , deux catégories d'utilisateurs différentes, peuvent accéder. Lecteurs sont les seuls à pouvoir lire la base de données, alors que Écrivains sont les seuls à pouvoir lire la base de données et la mettre à jour également. Utilisons IRCTC à titre d'exemple simple. Si nous souhaitons vérifier l'état d'un numéro de train , entrez simplement le numéro du train dans le système pour afficher les informations pertinentes sur le train. Seules les informations présentes sur le site Web sont affichées ici. L'opérateur de lecture est le suivant. Cependant, si nous souhaitons réserver un billet, nous devons remplir le formulaire de réservation de billets avec des détails tels que notre nom, notre âge, etc. Nous allons donc effectuer une opération d'écriture ici. Des ajustements seront apportés au Base de données IRCTC .

Le problème est que plusieurs personnes tentent simultanément d'accéder au Base de données IRCTC . Ils pourraient être un écrivain ou un lecteur . Le problème se pose si un lecteur utilise déjà la base de données et qu'un rédacteur y accède simultanément pour travailler sur les mêmes données. Un autre problème survient lorsqu'un écrivain utilise une base de données et qu'un lecteur accède aux mêmes informations que la base de données. Troisièmement, il existe une difficulté lorsqu'un rédacteur met à jour la base de données tandis qu'un autre tente de mettre à jour les données sur la même base de données. Le quatrième scénario se produit lorsque deux lecteurs tentent de récupérer le même matériel. Tous ces problèmes surviennent si le lecteur et l’écrivain utilisent les mêmes données de base de données.

Le sémaphore est une méthode utilisée pour résoudre ce problème. Regardons une illustration de la façon d'utiliser ce problème.

Processus de lecture :

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

Explication:

Dans ce code, nous avons les données variables partagées et les nombre de lecteurs rc . Le par rapport à l'état La variable est utilisée pour limiter l'accès du processus d'écriture , et le mutex est utilisé pour garantir l’exclusion mutuelle pour l’accès aux données partagées.

Le processus de lecture est représenté par le fonction lecteur() . Le nombre de lecteurs (rc) est augmenté avant d’atteindre le verrouillage mutex . Il utilise pthread_cond_wait() attendre le par rapport à l'état variable si c'est le premier lecteur (rc == 1) . En conséquence, les écrivains ne pourront pas écrire tant que tous les lecteurs n’auront pas terminé.

Le processus de lecture vérifie s'il s'agit bien du dernier lecteur (rc == 0) et abaisse le lecteur compter (rc--) après avoir lu les données partagées. Si c'était, pthread_cond_signal() signale le par rapport à l'état variable pour permettre aux processus d'écriture en attente de continuer.

En utilisant le pthread_create() et Fonctions pthread_join() , nous nouveau et rejoindre plusieurs fils de discussion dans le fonction principale . Un identifiant individuel est attribué à chaque fil de lecture à des fins d'identification.

Processus de rédaction :

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

Dans l'exemple ci-dessus, comme pour processus de lecture , une opération dite d'attente est effectuée sur 'par rapport' lorsqu'un utilisateur souhaite accéder aux données ou à l'objet. Après cela, le nouvel utilisateur ne pourra plus accéder à l'objet. Et une fois que l'utilisateur a fini d'écrire, une autre opération de signal est effectuée sur par rapport .

2. Problème de verrouillage et de déverrouillage :

L'idée d'un mutex est utilisé en multithreading en C pour garantir qu'il n'y aura pas de condition de course entre le fils de discussion . Lorsque plusieurs threads commencent à traiter les mêmes données en même temps, cette situation est appelée courses . Cependant, si ces circonstances existent, nous devons le faire. Nous utilisons le le verrou du mutex() et fonctions unlock() pour sécuriser une section particulière de code pour un thread spécifique. De telle sorte qu’un autre thread ne peut pas commencer à effectuer la même opération. Le 'section/région critique' est le nom donné à cette zone de code protégée. Avant d'utiliser les ressources partagées, nous en installons beaucoup dans une certaine zone, et une fois que nous avons fini de les utiliser, nous les débloquons une fois de plus.

Examinons le fonctionnement du mutex de verrouillage et de déverrouillage en multithreading en C :

Exemple:

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

Explication:

qu'est-ce que la commande d'exportation sous Linux

Dans cet exemple ci-dessus, nous expliquons comment nous verrouillage et ouvrir une certaine région de code qui nous protège de la situation de course. 'pthread_mutex_t' est utilisé comme un initialiseur dans l'exemple ci-dessus. 'pthread_mutex_lock' est alors écrit avant le début du code que l’on souhaite verrouiller. Le codage que nous souhaitons verrouiller est ensuite terminé. Ensuite, le verrouillage du code est terminé par 'pthread_mutex_unlock' ; à l’avenir, aucun code ne sera en mode verrouillage.

Le problème du philosophe de la restauration :

L'un des problèmes classiques de la synchronisation est le problème de philosophe à manger . Une simple allocation de ressources pour plusieurs processus est nécessaire mais ne devrait pas entraîner une impasse ou faim . Le problème de philosophe à manger peut être considéré comme une représentation simple d’un certain nombre de processus, dont chacun exige des ressources. Étant donné que chacun de ces processus nécessite une allocation de ressources, il est nécessaire de répartir ces ressources entre tous les processus afin qu'aucun processus ne reste bloqué ou ne cesse de fonctionner.

Supposons qu'il y ait cinq philosophes assis à la même table. table en forme de cercle . Ils mangent à un moment donné et réfléchissent à quelque chose à un autre. Autour de la table ronde, les philosophes sont répartis équitablement sur les chaises. De plus, il y a un bol de riz et cinq baguettes pour chaque philosophe au milieu de la table. Quand la philosophe sent qu’elle ne peut pas interagir avec ses collègues assis à proximité.

Une philosophe prend parfois deux baguettes lorsqu’elle a faim. Elle choisit deux baguettes chez ses voisins, une sur elle gauche et un sur elle droite -qui sont à portée de main. Mais le philosophe ne doit jamais prendre plus d’une baguette à la fois. Elle ne pourra évidemment pas ramasser la baguette que le voisin utilise.

Exemple:

Utilisons un exemple pour démontrer comment cela est implémenté en 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;>

Explication:

Baguettes peut être représenté par un sémaphore. Puisqu'il y a baguettes sur la table et qu'aucun philosophe n'en a choisi, tous les composants des baguettes sont d'abord initialisés à 1 . Maintenant que baguette[i] a été choisi comme premier baguette. baguette[i] et baguette[(i+1)%5] sont soumis à la première opération d'attente. Ces opération d'attente des baguettes indique que le philosophe les a récupérés. Le processus de consommation commence une fois que le philosophe choisit son baguette . L'opération de signalisation s'effectue désormais sur le baguettes [i] et [(je+1)%5] une fois que le philosophe a fini de manger. Le philosophe se rendort alors.

Pour déterminer si le sous-fil a rejoint le fil principal ou non, nous avons utilisé le Fonction pthread_join . De même, nous avons vérifié si le mutex le verrou a été initialisé à l'aide du pthread_mutex_init méthode.

Pour initialiser et vérifier si le nouveau thread a été créé ou non, nous avons utilisé le fonction pthread_create . De la même manière, nous avons détruit le verrouillage mutex en utilisant le pthread_mutex_destroy fonction.

Le problème producteur-consommateur :

Un problème courant avec la synchronisation des processus multithread est le problème producteur-consommateur . Deux processus y sont présents : le premier est le processus du producteur , et le second est le processus du consommateur . De plus, on suppose que les deux opérations se déroulent simultanément et en parallèle. De plus, il s’agit d’un processus coopératif, ce qui implique qu’ils partagent quelque chose les uns avec les autres. Il est important que lorsque le tampon est complet , le producteur ne peut pas ajouter de données. Lorsque le tampon est vide, le consommateur ne peut pas extraire les données du tampon car la taille commune du tampon entre le producteur et le consommateur est fixé . Le problème est posé de cette façon. Ainsi, pour mettre en œuvre le problème Producteur-Consommateur et le résoudre, nous utiliserons l’idée de programmation parallèle.

Exemple:

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

Sortir:

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

Explication:

Nous effectuons deux tâches. Les fonctions consommateur() et producteur() indiquer l'état et le fonctionnement du consommateur et producteur . Le Méthode producteur() va créer le verrouillage mutex et déterminer si le tampon est complet quand on l'appelle. Lorsque le tampon est plein, rien ne sera produit. Sinon, ce sera le cas créer , et puis, après le production , il se mettra en veille pour débloquer le verrouillage mutex . Comme le producteur , le consommateur crée d'abord le verrouillage mutex , vérifie le tampon , consomme le produit , puis libère le verrou avant de se rendormir.

UN compteur (x) sera utilisé pendant la fabrication et continuera de croître jusqu'à ce que le fabricant produise l'article. Cependant, le consommateur fabriquera moins de produits identiques. article (x) .

Conclusion:

L'idée d'utiliser deux ou plus de discussions exécuter un programme est appelé multithreading dans le langage de programmation C. Multithreading permet l'exécution simultanée de plusieurs tâches. Le composant exécutable le plus simple d'un programme est un fil . Le processus est l'idée selon laquelle une tâche peut être accomplie en la divisant en plusieurs parties plus petites. sous-processus .

Le fichier d'en-tête pthread.h est nécessaire pour implémenter le multithreading en C car cela ne peut pas être fait directement.