Last active
September 5, 2018 06:00
-
-
Save nicky-zs/c5b3e3324658cd84e21a065ff670ebcf to your computer and use it in GitHub Desktop.
The classic memory model problems on Intel x86-64 multi-core systems. Return values of system calls or library calls are NOT CHECKED because they are only demos.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <pthread.h> | |
#include <semaphore.h> | |
pthread_t t1, t2; | |
sem_t sem_start1, sem_start2, sem_end; | |
int A, B, X, Y; | |
void *f1(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start1); | |
A = 1; | |
Y = B; | |
sem_post(&sem_end); | |
} | |
} | |
void *f2(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start2); | |
B = 1; | |
X = A; | |
sem_post(&sem_end); | |
} | |
} | |
int main(int argc, char *argv[]) { | |
sem_init(&sem_start1, 0, 0); | |
sem_init(&sem_start2, 0, 0); | |
sem_init(&sem_end, 0, 0); | |
pthread_create(&t1, NULL, f1, NULL); | |
pthread_create(&t2, NULL, f2, NULL); | |
for (;;) { | |
A = B = X = Y = 0; | |
sem_post(&sem_start1); | |
sem_post(&sem_start2); | |
sem_wait(&sem_end); | |
sem_wait(&sem_end); | |
if (X == 0 && Y == 0) { | |
printf("%lu: X = %d, Y = %d\n", time(NULL), X, Y); | |
} | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <pthread.h> | |
#include <semaphore.h> | |
pthread_t t1, t2; | |
sem_t sem_start1, sem_start2, sem_end; | |
int A, B, X, Y; | |
void *f1(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start1); | |
A = 1; | |
__sync_synchronize(); // or _mm_mfence() from emmintrin.h | |
Y = B; | |
sem_post(&sem_end); | |
} | |
} | |
void *f2(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start2); | |
B = 1; | |
__sync_synchronize(); // or _mm_mfence() from emmintrin.h | |
X = A; | |
sem_post(&sem_end); | |
} | |
} | |
int main(int argc, char *argv[]) { | |
sem_init(&sem_start1, 0, 0); | |
sem_init(&sem_start2, 0, 0); | |
sem_init(&sem_end, 0, 0); | |
pthread_create(&t1, NULL, f1, NULL); | |
pthread_create(&t2, NULL, f2, NULL); | |
for (;;) { | |
A = B = X = Y = 0; | |
sem_post(&sem_start1); | |
sem_post(&sem_start2); | |
sem_wait(&sem_end); | |
sem_wait(&sem_end); | |
if (X == 0 && Y == 0) { | |
printf("%lu: X = %d, Y = %d\n", time(NULL), X, Y); | |
} | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <pthread.h> | |
#include <semaphore.h> | |
pthread_t t1, t2; | |
sem_t sem_start1, sem_start2, sem_end; | |
int A, B, X; | |
void *f1(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start1); | |
A = 1; | |
X = B; | |
sem_post(&sem_end); | |
} | |
} | |
void *f2(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start2); | |
B = 1; | |
X = A; | |
sem_post(&sem_end); | |
} | |
} | |
int main(int argc, char *argv[]) { | |
sem_init(&sem_start1, 0, 0); | |
sem_init(&sem_start2, 0, 0); | |
sem_init(&sem_end, 0, 0); | |
pthread_create(&t1, NULL, f1, NULL); | |
pthread_create(&t2, NULL, f2, NULL); | |
for (;;) { | |
A = B = X = 0; | |
sem_post(&sem_start1); | |
sem_post(&sem_start2); | |
sem_wait(&sem_end); | |
sem_wait(&sem_end); | |
if (X == 0) { | |
printf("%lu: X = %d\n", time(NULL), X); | |
} | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <pthread.h> | |
#include <semaphore.h> | |
pthread_t t1, t2; | |
sem_t sem_start1, sem_start2, sem_end; | |
int A, B; | |
volatile int X; | |
void *f1(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start1); | |
A = 1; | |
__sync_synchronize(); // or _mm_mfence() from emmintrin.h | |
while (!__sync_bool_compare_and_swap(&X, X, B)) // CAS, no intrinsic replacement | |
; | |
sem_post(&sem_end); | |
} | |
} | |
void *f2(void *arg) { | |
for (;;) { | |
sem_wait(&sem_start2); | |
B = 1; | |
__sync_synchronize(); // or _mm_mfence() from emmintrin.h | |
while (!__sync_bool_compare_and_swap(&X, X, A)) // CAS, no intrinsic replacement | |
; | |
sem_post(&sem_end); | |
} | |
} | |
int main(int argc, char *argv[]) { | |
sem_init(&sem_start1, 0, 0); | |
sem_init(&sem_start2, 0, 0); | |
sem_init(&sem_end, 0, 0); | |
pthread_create(&t1, NULL, f1, NULL); | |
pthread_create(&t2, NULL, f2, NULL); | |
for (;;) { | |
A = B = X = 0; | |
sem_post(&sem_start1); | |
sem_post(&sem_start2); | |
sem_wait(&sem_end); | |
sem_wait(&sem_end); | |
if (X == 0) { | |
printf("%lu: X = %d\n", time(NULL), X); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
All the codes can be translated into Java and works on JVMs. However, the memory model of JVM seems not to be as strong as x86 platforms because it seems that JVMs allow reordering stores with stores or loads.
PS: On JVMs, a volatile write can act as a full memory fence for there will be a mfence instruction after any writes of a volatile variable. And AtomicXxx.set() has the memory effects of writing a volatile variable.