1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// !> Multi-threaded sum using a single global variable and mutexes

/** 
 * Usage
 *
 * ./sum <from> <to>
 */
#include <stdio.h>
#include <stdlib.h>

#include <sys/wait.h>
#include <unistd.h>

#include <pthread.h>

#include <assert.h>
long sum = 0;
pthread_mutex_t sum_lock = PTHREAD_MUTEX_INITIALIZER;

typedef struct {
  long from;
  long to;
} sum_args_t;

long sum_from_to(long from, long to) {

  for (long i = from; i <= to; ++i) {
    // enter if allowed, lock entry
    //while (sum_lock) { /* wait */ };
    //sum_lock = 1;
    pthread_mutex_lock(&sum_lock);
    sum += i; // not performed atomically
    pthread_mutex_unlock(&sum_lock);
    //sum_lock = 0; //unlock
    // unlock entry, and exit

    // movq sum, %rax
    // addq %rcx, %rax
    // movq %rax, sum
//
//   sum        Thread 1          Thread 2
//   100        read 100          ---
//   100        add 12 to 100
//   112        write 112 to sum
//   112        read 112 from sum 
//   112        ---               read 112 from sum
//   112                          add 52 to 112
//   164                          write 164 to sum
//   164        add 13 112        ---
//   125        write 125 to sum
  }
  fprintf(stderr, "Completed %ld to %ld\n", from, to);
}

void *sum_thread(void *args) {
  sum_args_t *sum_args = args;
  sum_from_to(sum_args->from, sum_args->to);
  return NULL;
}

int main(int argc, char **argv) {
  assert(argc >= 3);

  long from = atol(argv[1]);
  long to = atol(argv[2]);

  pthread_t th;

  sum_args_t sum_args = { .from = from, .to = to / 2 };
  // perform sum of 'from' to 'to / 2' in helper thread 
  assert(0 == pthread_create(&th, NULL, sum_thread, &sum_args));

  // perform sum of  '(to / 2) + 1' to 'to'
  sum_from_to(to / 2 + 1, to);

  assert(0 == pthread_join(th, NULL));
  printf("%ld\n", sum);

  return 0;
}