RosettaCodeData/Task/Atomic-updates/C/atomic-updates-1.c

112 lines
2.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#define N_BUCKETS 15
pthread_mutex_t bucket_mutex[N_BUCKETS];
int buckets[N_BUCKETS];
pthread_t equalizer;
pthread_t randomizer;
void transfer_value(int from, int to, int howmuch)
{
bool swapped = false;
if ( (from == to) || ( howmuch < 0 ) ||
(from < 0 ) || (to < 0) || (from >= N_BUCKETS) || (to >= N_BUCKETS) ) return;
if ( from > to ) {
int temp1 = from;
from = to;
to = temp1;
swapped = true;
howmuch = -howmuch;
}
pthread_mutex_lock(&bucket_mutex[from]);
pthread_mutex_lock(&bucket_mutex[to]);
if ( howmuch > buckets[from] && !swapped )
howmuch = buckets[from];
if ( -howmuch > buckets[to] && swapped )
howmuch = -buckets[to];
buckets[from] -= howmuch;
buckets[to] += howmuch;
pthread_mutex_unlock(&bucket_mutex[from]);
pthread_mutex_unlock(&bucket_mutex[to]);
}
void print_buckets()
{
int i;
int sum=0;
for(i=0; i < N_BUCKETS; i++) pthread_mutex_lock(&bucket_mutex[i]);
for(i=0; i < N_BUCKETS; i++) {
printf("%3d ", buckets[i]);
sum += buckets[i];
}
printf("= %d\n", sum);
for(i=0; i < N_BUCKETS; i++) pthread_mutex_unlock(&bucket_mutex[i]);
}
void *equalizer_start(void *t)
{
for(;;) {
int b1 = rand()%N_BUCKETS;
int b2 = rand()%N_BUCKETS;
int diff = buckets[b1] - buckets[b2];
if ( diff < 0 )
transfer_value(b2, b1, -diff/2);
else
transfer_value(b1, b2, diff/2);
}
return NULL;
}
void *randomizer_start(void *t)
{
for(;;) {
int b1 = rand()%N_BUCKETS;
int b2 = rand()%N_BUCKETS;
int diff = rand()%(buckets[b1]+1);
transfer_value(b1, b2, diff);
}
return NULL;
}
int main()
{
int i, total=0;
for(i=0; i < N_BUCKETS; i++) pthread_mutex_init(&bucket_mutex[i], NULL);
for(i=0; i < N_BUCKETS; i++) {
buckets[i] = rand() % 100;
total += buckets[i];
printf("%3d ", buckets[i]);
}
printf("= %d\n", total);
// we should check if these succeeded
pthread_create(&equalizer, NULL, equalizer_start, NULL);
pthread_create(&randomizer, NULL, randomizer_start, NULL);
for(;;) {
sleep(1);
print_buckets();
}
// we do not provide a "good" way to stop this run, so the following
// is never reached indeed...
for(i=0; i < N_BUCKETS; i++) pthread_mutex_destroy(bucket_mutex+i);
return EXIT_SUCCESS;
}