計算機科学のブログ

C - スレッド - 並列の世界 - POSIXスレッドライブラリ(pthread), スレッドセーフ, ミューテックス, ロック

Head First C ―頭とからだで覚えるCの基本David Griffiths(著)、 Dawn Griffiths(著)、 中田 秀基(監修)、 木下 哲也(翻訳)、 O’Reilly Media)の 12章(スレッド - 並列の世界)、p.516(長いエクササイズ)の解答を求めてみる。

Makefile

all: a.out
	./a.out

a.out: main.c
	cc main.c

コード

main.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>

void error(char *msg)
{
    fprintf(stderr, "%s:%s\n", msg, strerror(errno));
    exit(1);
}
int beers_a = 2000000;
pthread_mutex_t beers_lock_a = PTHREAD_MUTEX_INITIALIZER;
void *drink_lots_a(void *a)
{
    pthread_mutex_lock(&beers_lock_a);
    for (size_t i = 0; i < 100000; i++)
    {
        beers_a--;
    }
    pthread_mutex_unlock(&beers_lock_a);
    printf("beers_a = %i\n", beers_a);
    return NULL;
}
int beers_b = 2000000;
pthread_mutex_t beers_lock_b = PTHREAD_MUTEX_INITIALIZER;

void *drink_lots_b(void *a)
{
    for (size_t i = 0; i < 100000; i++)
    {
        pthread_mutex_lock(&beers_lock_b);
        beers_b--;
        pthread_mutex_unlock(&beers_lock_b);
    }
    printf("beers_b = %i\n", beers_b);
    return NULL;
}
int main()
{
    // 上から順番通り
    size_t count = 20;
    pthread_t threads_a[count];
    printf("壁にはビールが%i本\n%i本のビール\n", beers_a, beers_a);
    for (size_t t = 0; t < count; t++)
    {
        if (pthread_create(&threads_a[t], NULL, drink_lots_a, NULL) == -1)
        {
            char s[255];
            sprintf(s, "スレッドthreads[%zu]を作成できません。", t);
            error(s);
        }
    }
    void *result_a;
    for (size_t t = 0; t < count; t++)
    {
        if (pthread_join(threads_a[t], &result_a) == -1)
        {
            char s[255];
            sprintf(s, "スレッドthreads[%zu]をジョインできません。", t);
            error(s);
        }
    }
    printf("現在、壁にはビールが%i本あります。\n", beers_a);

    pthread_t threads_b[count];
    printf("壁にはビールが%i本\n%i本のビール\n", beers_b, beers_b);
    for (size_t t = 0; t < count; t++)
    {
        if (pthread_create(&threads_b[t], NULL, drink_lots_b, NULL) == -1)
        {
            char s[255];
            sprintf(s, "スレッドthreads[%zu]を作成できません。", t);
            error(s);
        }
    }
    void *result_b;
    for (size_t t = 0; t < count; t++)
    {
        if (pthread_join(threads_b[t], &result_b) == -1)
        {
            char s[255];
            sprintf(s, "スレッドthreads[%zu]をジョインできません。", t);
            error(s);
        }
    }
    printf("現在、壁にはビールが%i本あります。\n", beers_b);
}

入出力結果(Terminal, Zsh)

% make
cc main.c
./a.out
壁にはビールが2000000本
2000000本のビール
beers_a = 1900000
beers_a = 1800000
beers_a = 1700000
beers_a = 1600000
beers_a = 1500000
beers_a = 1400000
beers_a = 1300000
beers_a = 1200000
beers_a = 1100000
beers_a = 1000000
beers_a = 900000
beers_a = 800000
beers_a = 700000
beers_a = 600000
beers_a = 500000
beers_a = 400000
beers_a = 300000
beers_a = 200000
beers_a = 100000
beers_a = 0
現在、壁にはビールが0本あります。
壁にはビールが2000000本
2000000本のビール
beers_b = 236854
beers_b = 165839
beers_b = 123423
beers_b = 109334
beers_b = 67909
beers_b = 66788
beers_b = 63692
beers_b = 54163
beers_b = 47046
beers_b = 46461
beers_b = 43156
beers_b = 38298
beers_b = 34861
beers_b = 26016
beers_b = 15507
beers_b = 14254
beers_b = 9705
beers_b = 4361
beers_b = 1437
beers_b = 0
現在、壁にはビールが0本あります。
%