logo

MULTITHREADING EM C

Introdução:

Em C, o termo 'multithreading' descreve o uso de numerosos tópicos simultaneamente. Cada thread faz um tarefa diferente . Devido à natureza simultânea do multithreading, muitas tarefas podem ser realizadas ao mesmo tempo. Adicionalmente, multithreading reduz o Uso de recursos da CPU . Existem duas categorias de multitarefa: baseado em processo e baseado em thread . Quando algo é descrito como multithreading, significa que pelo menos dois ou talvez mais threads estão sendo executados no mesmo processo ao mesmo tempo. Devemos primeiro entender o que são um thread e um processo para compreender o multithreading em C. Vejamos esses assuntos para obter uma melhor compreensão.

tamanho do vetor c++

O que são processos e threads?

A fio é o edifício fundamental bloquear da execução de qualquer processo. Um programa é composto por vários processos, e cada processo é composto por threads, que são unidades muito mais básicas. Portanto, o thread pode ser considerado o bloco de construção fundamental de um processo ou a unidade mais simples que determina em conjunto a utilização da CPU.

Os seguintes itens estão incluídos em um tópico:

ID do tópico:

É um especial ID do tópico que é gerado no momento da formação do thread e retido durante a duração desse thread específico.

Contador de programa:

É um valor que o cargas de hardware .

Um conjunto registrado:

É uma coleção de registros comuns .

Uma pilha:

É um resquício disso tópico específico .

Além disso, se dois threads trabalham simultaneamente no mesmo processo, eles compartilham código , seções de dados e outros recursos do sistema operacional, como arquivo abre e sinais . Um processo pesado, um tipo de processo convencional, pode controlar um thread. No entanto, um controle multithread tem a capacidade de abrir e executar múltiplas tarefas simultaneamente. O sistema se torna consideravelmente mais eficaz com o uso de threads, por isso eles são úteis.

A distinção entre solteiro e multithreading em C é explicado. Em primeiro lugar, é um processo de thread único . Como resultado, todo o bloco - incluindo o código, dados, etc.-é considerado como um processo, e esse processo possui apenas um thread. Isso significa que esta técnica irá completar apenas uma tarefa por vez. Mas há um processo multithread que se opõe a isso. Existem atividades como código, pilha, dados , e arquivos também, mas estão sendo executados por vários threads, cada um com sua própria pilha e registros. Dado que inúmeras tarefas podem ser concluídas ao mesmo tempo nesta situação, o processo é conhecido como processo multithread .

Thread vem em duas variedades:

Tópico no nível do usuário:

Está no nível do usuário, como o nome indica. O kernel não tem acesso aos seus dados.

Thread no nível do kernel

O tipo de thread refere-se ao relacionamento do thread com o kernel e o sistema operacional do sistema.

Processo- A série de etapas executadas para executar um programa pode ser chamada de processo . Um programa não é executado imediatamente quando é executado. É dividido em algumas etapas básicas que são realizadas sequencialmente de forma organizada para eventualmente levar à execução de um processo.

Um processo que foi dividido em etapas menores é chamado de 'clone ou processo filho', enquanto o processo original é chamado de processo 'pai' . Na memória, cada processo utiliza uma certa quantidade de espaço que não é compartilhada com nenhum outro processo.

Um procedimento passa por algumas etapas antes da execução.

NOVO-

Nesta situação, um novo processo é gerado .

PREPARAR-

Quando um processo está preparado e aguardando a atribuição de um processador, ele está neste estado.

CORRENDO-

supw

Quando o processo está ativo, é o estado.

ESPERANDO-

Quando um processo está neste estado, algo está esperando acontecer.

TERMINADO-

É o estado em que o procedimento está sendo realizado.

Por que C é multithread?

Multithreading na ideia C pode ser aproveitado através do paralelismo para melhorar uma funcionalidade do aplicativo . Considere o caso em que você tem várias guias abertas em uma janela do navegador. Então, cada guia opera simultaneamente e pode ser chamada de Fio . Supondo que usamos Microsoft Excel , um thread irá gerenciar formatação de texto , e um thread será lidar com entrada . Portanto, o recurso multithreading do C simplifica a execução de múltiplas tarefas ao mesmo tempo. A criação de um thread é consideravelmente mais rápida. A transferência de contexto entre threads acontece mais rapidamente. Além disso, a comunicação entre threads pode ser feita mais rapidamente e o encerramento de threads é simples.

Como escrever programas C para multithreading?

Embora os aplicativos multithreading não sejam integrados à linguagem C, isso é possível dependendo do sistema operacional. O biblioteca padrão threads.h é usado para implementar a ideia de multithreading em C . No entanto, atualmente não existe nenhum compilador que possa fazer isso. Devemos empregar implementações específicas de plataforma, como o 'POSIX' biblioteca de threads, usando o arquivo de cabeçalho pthread.h , se quisermos usar multithreading em C. 'Pthreads' é outro nome para isso. A POSIX thread pode ser criado das seguintes maneiras:

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

Nesse caso, Pthread_create cria um novo thread para torná-lo executável. Ele permite que você implemente multithreading em C quantas vezes quiser em seu código. Os parâmetros e suas descrições anteriores estão listados aqui.

fio:

É um identificação singular que o retornos de subprocesso .

atributo:

Quando queremos definir atributos de thread, usamos isto atributo opaco .

rotina_inicial:

Quando rotina_inicial é gerado, o thread executará uma rotina.

um milhão em números

argumento:

O parâmetro que o rotina_inicial recebe. NULO será usado se nenhum argumento for fornecido.

Certos exemplos de multithreading C

Aqui estão alguns exemplos de problemas de multithreading em C.

1. A questão do leitor-escritor

Um problema comum do sistema operacional com a sincronização de processos é o problema de leitor/escritor . Suponha que temos um banco de dados que Leitores e Escritoras , duas categorias de usuários diferentes, podem acessar. Leitores são os únicos que podem ler o banco de dados, enquanto Escritoras são os únicos que podem ler o banco de dados e atualizá-lo também. Vamos usar IRCTC como um exemplo simples. Se desejarmos verificar o status de um determinado número do trem , basta inserir o número do trem no sistema para visualizar as informações pertinentes do trem. Apenas as informações presentes no site são mostradas aqui. O operador de leitura é este. Porém, se quisermos reservar uma passagem, devemos preencher o formulário de reserva de passagem com dados como nome, idade, etc. Então, realizaremos uma operação de gravação aqui. Haverá alguns ajustes feitos no Banco de dados IRCTC .

O problema é que várias pessoas estão tentando acessar simultaneamente o Banco de dados IRCTC . Eles podem ser um escritor ou um leitor . O problema surge se um leitor já estiver utilizando o banco de dados e um gravador o acessar simultaneamente para trabalhar nos mesmos dados. Outro problema surge quando um escritor usa um banco de dados e um leitor acessa as mesmas informações que o banco de dados. Em terceiro lugar, há uma dificuldade quando um autor atualiza o banco de dados enquanto outro tenta atualizar dados no mesmo banco de dados. O quarto cenário ocorre quando dois leitores tentam recuperar o mesmo material. Todos esses problemas surgem se o leitor e o gravador usarem os mesmos dados do banco de dados.

O semáforo é um método empregado para resolver esse problema. Vejamos uma ilustração de como usar esse problema.

Processo do leitor:

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

Explicação:

Neste código, temos os dados da variável compartilhada e o contagem de leitores rc . O condição ruim variável é usada para limitar o acesso para o processo de escritor , e a mutex é usado para garantir a exclusão mútua no acesso aos dados compartilhados.

O processo de leitura é representado pelo função leitor() . O contagem de leitores (rc) é aumentado antes de atingir o bloqueio mutex . Ele usa pthread_cond_wait() esperar no condição ruim variável se for o primeiro leitor (rc == 1) . Como resultado, os escritores serão impedidos de escrever até que todos os leitores tenham concluído.

O processo leitor verifica se foi o último leitor (rc == 0) e abaixa o leitor contar (rc--) depois de ler os dados compartilhados. Se fosse, pthread_cond_signal() sinaliza o condição ruim variável para permitir que os processos de gravação em espera continuem.

Usando o pthread_create() e Funções pthread_join() , nós novo e juntar vários threads de leitor no função principal . Um ID individual é atribuído a cada thread do leitor para fins de identificação.

Processo do escritor:

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

No exemplo acima, igual ao processo de leitura , uma operação conhecida como operação de espera é executada em 'errado' quando um usuário deseja acessar os dados ou objeto. Depois disso, o novo usuário não poderá acessar o objeto. E assim que o usuário terminar de escrever, outra operação de sinal é realizada no errado .

2. Problema de bloqueio e desbloqueio:

A ideia de um mutex é utilizado em multithreading em C para garantir que não haverá condição de corrida Entre o tópicos . Quando vários threads começam a processar os mesmos dados ao mesmo tempo, esta circunstância é conhecida como corrida . No entanto, se essas circunstâncias existirem, devemos fazê-lo. Nós usamos o bloqueio do mutex() e funções de desbloqueio() para proteger uma seção específica de código para um thread específico. De tal forma que outro thread não pode começar a realizar a mesma operação. O 'seção/região crítica' é o nome dado a esta área de código protegida. Antes de utilizar os recursos compartilhados, configuramos um lote em uma determinada área, e assim que terminarmos de utilizá-los, os desbloqueamos mais uma vez.

Vamos examinar a operação do mutex para bloqueio e desbloqueio em multithreading em C:

Exemplo:

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

Explicação:

programação cobol

Neste exemplo acima, explicamos como podemos trancar e desbloquear uma determinada região do código que nos protege da situação de corrida. 'pthread_mutex_t' é usado como inicializador no exemplo acima. 'pthread_mutex_lock' é então escrito antes do início do código que queremos bloquear. A codificação que desejamos bloquear é finalizada depois disso. Depois disso, o bloqueio do código é finalizado usando 'pthread_mutex_unlock' ; daqui para frente, nenhum código estará no modo de bloqueio.

O problema do filósofo do jantar:

Um dos problemas clássicos da sincronização é a questão do filósofo do jantar . A alocação simples de recursos para vários processos é necessária, mas não deve resultar em impasse ou fome . O problema do filósofo jantar pode ser visto como uma representação direta de uma série de processos, cada um dos quais demanda recursos. Como cada um desses processos requer uma alocação de recursos, é necessário distribuir esses recursos por todos os processos para que nenhum processo fique preso ou pare de funcionar.

Suponha que haja cinco filósofos sentados em uma mesa em forma de círculo . Eles comem em um momento e ponderam sobre algo em outro. Ao redor da mesa redonda, os filósofos estão distribuídos uniformemente nas cadeiras. Além disso, há uma tigela de arroz e cinco pauzinhos para cada filósofo no meio da mesa. Quando a filósofa sente que não consegue interagir com os colegas que estão sentados nas proximidades.

Uma filósofa ocasionalmente pega dois pauzinhos quando fica com fome. Ela escolhe dois pauzinhos dos vizinhos - um esquerda e um nela certo -que são de fácil acesso. Mas o filósofo nunca deveria pegar mais de um pauzinho ao mesmo tempo. Obviamente ela não conseguirá pegar o pauzinho que o vizinho está usando.

Exemplo:

Vamos usar um exemplo para demonstrar como isso é implementado em C.

fila de prioridade java
 #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;>

Explicação:

Pauzinhos pode ser representado por um semáforo. Já que existem pauzinhos na mesa e nenhum filósofo escolheu um, todos os componentes dos pauzinhos são primeiro inicializados para 1 . Agora isso pauzinho[eu] foi escolhido como o primeiro pauzinho. pauzinho[eu] e pauzinho[(i+1)%5] estão sujeitos à primeira operação de espera. Esses operação de espera dos pauzinhos indica que o filósofo os pegou. O processo de comer começa quando o filósofo seleciona seu pauzinho . A operação do sinal é agora realizada no pauzinhos [eu] e [(i+1)%5] assim que o filósofo terminar de comer. O filósofo então volta a dormir.

Para determinar se o subtópico entrou no tópico principal ou não, usamos o Função pthread_join . Da mesma forma, verificamos se o mutex lock foi inicializado usando o pthread_mutex_init método.

Para inicializar e verificar se o novo thread foi criado ou não, utilizamos o função pthread_create . Semelhante a isso, destruímos o bloqueio mutex usando o pthread_mutex_destroy função.

O problema produtor-consumidor:

Um problema comum com a sincronização de processos multithreading é o problema produtor-consumidor . Nele estão presentes dois processos: o primeiro é o processo do produtor , e o segundo é o processo do consumidor . Além disso, assume-se que ambas as operações estão ocorrendo simultaneamente em paralelo. Além disso, são um processo cooperativo, o que implica que estão compartilhando algo entre si. É importante que quando o buffer for completo , o produtor não poderá adicionar dados. Quando o buffer está vazio, o consumidor não pode extrair dados do buffer porque o tamanho comum do buffer entre o produtor e o consumidor é fixo . A questão é colocada desta forma. Portanto, para implementar o problema Produtor-Consumidor e resolvê-lo, empregaremos a ideia de programação paralela.

Exemplo:

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

Saída:

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

Explicação:

Realizamos duas tarefas. As funções consumidor() e produtor() indicar o status e a operação do consumidor e produtor . O método produtor() criará o bloqueio mutex e determinar se o buffer é completo quando é chamado. Quando o buffer estiver cheio, nada será produzido. Se não, será criar , e então, após o Produção , ele irá dormir para desbloquear o bloqueio mutex . Como o produtor , o consumidor primeiro cria o bloqueio mutex , verifica o amortecedor , consome o produtos e, em seguida, libera o bloqueio antes de voltar a dormir.

A contador (x) será usado durante a fabricação e continuará crescendo até que o fabricante produza o item. No entanto, o consumidor produzirá menos produtos do mesmo tipo item (x) .

Conclusão:

A ideia de usar dois ou mais tópicos executar um programa é conhecido como multithreading na linguagem de programação C. Multithreading permite a execução simultânea de diversas tarefas. O componente executável mais simples de um programa é um fio . O processo é a ideia de que uma tarefa pode ser concluída dividindo-a em várias tarefas menores. subprocessos .

O arquivo de cabeçalho pthread.h é necessário para implementar multithreading em C, uma vez que não pode ser feito diretamente.