POSIX
discussioni
Ricerca…
Discussione semplice senza argomenti
Questo esempio di base conta a velocità diverse su due thread che chiamiamo sync (main) e async (new thread). Il thread principale conta 15 a 1Hz (1s) mentre il secondo conta a 10 a 0.5Hz (2s). Poiché il thread principale termina prima, usiamo pthread_join
per farlo attendere async to finish.
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
/* This is the function that will run in the new thread. */
void * async_counter(void * pv_unused) {
int j = 0;
while (j < 10) {
printf("async_counter: %d\n", j);
sleep(2);
j++;
}
return NULL;
}
int main(void) {
pthread_t async_counter_t;
int i;
/* Create the new thread with the default flags and without passing
* any data to the function. */
if (0 != (errno = pthread_create(&async_counter_t, NULL, async_counter, NULL))) {
perror("pthread_create() failed");
return EXIT_FAILURE;
}
i = 0;
while (i < 15) {
printf("sync_counter: %d\n", i);
sleep(1);
i++;
}
printf("Waiting for async counter to finish ...\n");
if (0 != (errno = pthread_join(async_counter_t, NULL))) {
perror("pthread_join() failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Copiato da qui: http://stackoverflow.com/documentation/c/3873/posix-threads/13405/simple-thread-without-arguments dove inizialmente era stato creato da M. Rubio-Roy .
Semplice utilizzo di mutex
La libreria di thread POSIX fornisce l'implementazione della primitiva mutex, utilizzata per l'esclusione reciproca. Mutex viene creato usando pthread_mutex_init
e distrutto usando pthread_mutex_destroy
. Ottenere un mutex può essere fatto usando pthread_mutex_lock
o pthread_mutex_trylock
, (a seconda se si desidera il timeout) e il rilascio di un mutex avviene tramite pthread_mutex_unlock
.
Segue un semplice esempio che utilizza un mutex per serializzare l'accesso alla sezione critica. Innanzitutto, l'esempio senza usare un mutex. Si noti che questo programma ha una corsa di dati dovuta all'accesso non sincronizzato a global_resource
da parte dei due thread. Di conseguenza, questo programma ha un comportamento non definito :
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
// Global resource accessible to all threads
int global_resource;
// Threading routine which increments the resource 10 times and prints
// it after every increment
void* thread_inc (void* arg)
{
for (int i = 0; i < 10; i++)
{
global_resource++;
printf("Increment: %d\n", global_resource);
// Make this thread slower, so the other one
// can do more work
sleep(1);
}
printf("Thread inc finished.\n");
return NULL;
}
// Threading routine which decrements the resource 10 times and prints
// it after every decrement
void* thread_dec (void* arg)
{
for (int i = 0; i < 10; i++)
{
global_resource--;
printf("Decrement: %d\n", global_resource);
}
printf("Thread dec finished.\n");
return NULL;
}
int main (int argc, char** argv)
{
pthread_t threads[2];
if (0 != (errno = pthread_create(&threads[0], NULL, thread_inc, NULL)))
{
perror("pthread_create() failed");
return EXIT_FAILURE;
}
if (0 != (errno = pthread_create(&threads[1], NULL, thread_dec, NULL)))
{
perror("pthread_create() failed");
return EXIT_FAILURE;
}
// Wait for threads to finish
for (int i = 0; i < 2; i++)
{
if (0 != (errno = pthread_join(threads[i], NULL))) {
perror("pthread_join() failed");
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Un possibile risultato è:
Increment: 1
Decrement: 0
Decrement: -1
Decrement: -2
Decrement: -3
Decrement: -4
Decrement: -5
Decrement: -6
Decrement: -7
Decrement: -8
Decrement: -9
Thread dec finished.
Increment: -8
Increment: -7
Increment: -6
Increment: -5
Increment: -4
Increment: -3
Increment: -2
Increment: -1
Increment: 0
Thread inc finished.
Ora, se vogliamo sincronizzare questi thread in modo che vogliamo prima incrementare o decrementare completamente verso l'alto o verso il basso, e poi farlo in modo diverso, dobbiamo usare una primitiva di sincronizzazione, come mutex:
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
// Global resource accessible to all threads
int global_resource;
// Mutex protecting the resource
pthread_mutex_t mutex;
// Threading routine which increments the resource 10 times and prints
// it after every increment
void* thread_inc (void* arg)
{
// Pointer to mutex is passed as an argument
pthread_mutex_t* mutex = arg;
// Execute the following code without interrupts, all the way to the
// point B
if (0 != (errno = pthread_mutex_lock(mutex)))
{
perror("pthread_mutex_lock failed");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 10; i++)
{
global_resource++;
printf("Increment: %d\n", global_resource);
// Make this thread slower, so the other one
// can do more work
sleep(1);
}
printf("Thread inc finished.\n");
// Point B:
if (0 != (errno = pthread_mutex_unlock(mutex)))
{
perror("pthread_mutex_unlock failed");
exit(EXIT_FAILURE);
}
return NULL;
}
// Threading routine which decrements the resource 10 times and prints
// it after every decrement
void* thread_dec (void* arg)
{
// Pointer to mutex is passed as an argument
pthread_mutex_t* mutex = arg;
if (0 != (errno = pthread_mutex_lock(mutex)))
{
perror("pthread_mutex_lock failed");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 10; i++)
{
global_resource--;
printf("Decrement: %d\n", global_resource);
}
printf("Thread dec finished.\n");
// Point B:
if (0 != (errno = pthread_mutex_unlock(mutex)))
{
perror("pthread_mutex_unlock failed");
exit(EXIT_FAILURE);
}
return NULL;
}
int main (int argc, char** argv)
{
pthread_t threads[2];
pthread_mutex_t mutex;
// Create a mutex with the default parameters
if (0 != (errno = pthread_mutex_init(&mutex, NULL)))
{
perror("pthread_mutex_init() failed");
return EXIT_FAILURE;
}
if (0 != (errno = pthread_create(&threads[0], NULL, thread_inc, &mutex)))
{
perror("pthread_create() failed");
return EXIT_FAILURE;
}
if (0 != (errno = pthread_create(&threads[1], NULL, thread_dec, &mutex)))
{
perror("pthread_create() failed");
return EXIT_FAILURE;
}
// Wait for threads to finish
for (int i = 0; i < 2; i++)
{
if (0 != (errno = pthread_join(threads[i], NULL))) {
perror("pthread_join() failed");
return EXIT_FAILURE;
}
}
// Both threads are guaranteed to be finished here, so we can safely
// destroy the mutex
if (0 != (errno = pthread_mutex_destroy(&mutex)))
{
perror("pthread_mutex_destroy() failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Una delle possibili uscite è
Increment: 1
Increment: 2
Increment: 3
Increment: 4
Increment: 5
Increment: 6
Increment: 7
Increment: 8
Increment: 9
Increment: 10
Thread inc finished.
Decrement: 9
Decrement: 8
Decrement: 7
Decrement: 6
Decrement: 5
Decrement: 4
Decrement: 3
Decrement: 2
Decrement: 1
Decrement: 0
Thread dec finished.
L'altro output possibile sarebbe inverso, nel caso che thread_dec
ottenuto prima il mutex.