はじめに
CSAPPを読んで、並行プログラミングの基礎を学んでいます。Mac環境だとサンプルコードを少しいじる必要があったので、メモとしてまとめます。
自分の環境です。
❯ sw_vers
ProductName: macOS
ProductVersion: 11.6
BuildVersion: 20G165
スレッドが同期エラーを起こすbadコード
badcnt.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
volatile long cnt = 0;
void *thread(void *vargp)
{
long i;
long niters = *((long *)vargp);
for (i = 0; i < niters; i++)
{
cnt++;
}
return NULL;
}
int main(int argc, char **argv)
{
long niters;
pthread_t tid1, tid2;
if (argc != 2) {
printf("Usage: %s <niters>\n", argv[0]);
exit(0);
}
niters = atoi(argv[1]);
pthread_create(&tid1, NULL, thread, (void *)&niters);
pthread_create(&tid2, NULL, thread, (void *)&niters);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
if (cnt != niters * 2)
printf("BOOM! cnt = %ld\n", cnt);
else
printf("OK cnt=%ld\n", cnt);
return 0;
}
### 実行結果
❯ gcc badcnt.c && ./a.out 1000000
BOOM! cnt = 1011960
## mutexを使用して相互排他を行ったコード
goodcnt_mutex.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
volatile long cnt = 0;
pthread_mutex_t lock;
void *thread(void *vargp)
{
long i;
long niters = *((long *)vargp);
for (i = 0; i < niters; i++)
{
pthread_mutex_lock(&lock);
cnt++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(int argc, char **argv)
{
long niters;
pthread_t tid1, tid2;
pthread_mutex_init(&lock, NULL);
if (argc != 2) {
printf("Usage: %s <niters>\n", argv[0]);
exit(0);
}
niters = atoi(argv[1]);
pthread_create(&tid1, NULL, thread, (void *)&niters);
pthread_create(&tid2, NULL, thread, (void *)&niters);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
if (cnt != niters * 2)
printf("BOOM! cnt = %ld\n", cnt);
else
printf("OK cnt=%ld\n", cnt);
return 0;
}
### 実行結果
❯ gcc goodcnt_mutex.c && ./a.out 1000000
OK cnt=2000000
## セマフォを使用して相互排他を行ったコード
goodcnt_sem.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
volatile long cnt = 0;
sem_t *mutex;
void *thread(void *vargp)
{
long i;
long niters = *((long *)vargp);
for (i = 0; i < niters; i++)
{
sem_wait(mutex);
cnt++;
sem_post(mutex);
}
return NULL;
}
int main(int argc, char **argv)
{
long niters;
pthread_t tid1, tid2;
mutex = sem_open("/mutex", O_CREAT, 0644, 1);
if (argc != 2) {
printf("Usage: %s <niters>\n", argv[0]);
exit(0);
}
niters = atoi(argv[1]);
pthread_create(&tid1, NULL, thread, (void *)&niters);
pthread_create(&tid2, NULL, thread, (void *)&niters);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
if (cnt != niters * 2)
printf("BOOM! cnt = %ld\n", cnt);
else
printf("OK cnt=%ld\n", cnt);
return 0;
}
### 実行結果
❯ gcc goodcnt_sem.c && ./a.out 1000000
OK cnt=2000000