2023年3月27日月曜日

高野spinlock::mutex,semaphore,barrier(spin/cv/lib),rwlock,スレッドやCV生成は謎

mutex スピンロック方式

#include <pthread.h>

#include <stdbool.h>

#include <stdio.h>

bool test_and_set(volatile bool *p) {

    return __sync_lock_test_and_set(p, 1);

}

void tas_release(volatile bool *p) {

    return __sync_lock_release(p);

}

void spinlock_acquire(volatile bool *lock) { // <1>

    for (;;) {

        while(*lock); // <2>

        if (!test_and_set(lock))

            break;

    }

    // while (test_and_set(lock)); より効率的

}


void spinlock_release(bool *lock) {

    tas_release(lock);

}

bool lock = false; // 共有変数


void* some_func() {

    spinlock_acquire(&lock); // ロック獲得 <1>

       printf("hi\n");// critical section

    spinlock_release(&lock);

    return 0;

}


int main(int argc, char *argv[]) {

    // スレッド生成

    pthread_t th1, th2;


    if (pthread_create(&th1, NULL, some_func, NULL) != 0) {

        perror("pthread_create"); return -1;

    }

    if (pthread_create(&th2, NULL, some_func, NULL) != 0) {

        perror("pthread_create"); return -1;

    }

    // スレッドの終了を待機

    if (pthread_join(th1, NULL) != 0) {

        perror("pthread_join"); return -1;

    }

---------------------------------------------------------------------------------

セマフォ スピンロック方式

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

#define NUM 4 // セマフォの数

#define NUM_THREADS 10 // スレッド数

#define NUM_LOOP 10 // スレッド内のループ数

int cnt = 0; // 共有変数

void semaphore_acquire(volatile int *cnt) { // <1>

    for (;;) {

        while (*cnt >= NUM); // <2>

        __sync_fetch_and_add(cnt, 1); // <3>

        if (*cnt <= NUM) // <4>

            break;

        __sync_fetch_and_sub(cnt, 1); // <5>

    }

}

void semaphore_release(int *cnt) {

    __sync_fetch_and_sub(cnt, 1); // <6>

}

void *th(void *arg) {

    for (int i = 0; i < NUM_LOOP; i++) {

        semaphore_acquire(&cnt);   

  printf("%d\n",cnt);

         // printf("helo\n");

        semaphore_release(&cnt);

    }

    return NULL;

}

int main(int argc, char *argv[]) {

    // スレッド生成

    pthread_t v[NUM_THREADS];

    for (int i = 0; i < NUM_THREADS; i++) {

        pthread_create(&v[i], NULL, th, NULL);

    }

    for (int i = 0; i < NUM_THREADS; i++) {

        pthread_join(v[i],NULL);

    }

    printf("OK!\n");

    return 0;

}

----------------------------------------------------------------
条件変数でバリア同期するのが一般的
// barrier.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

pthread_mutex_t barrier_mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t barrier_cond = PTHREAD_COND_INITIALIZER;

void barrier(volatile int *cnt, int max){
    if (pthread_mutex_lock(&barrier_mut) != 0){
        perror("pthread_mutex_lock");
        exit(-1);
    }

    (*cnt)++;

    if(*cnt==max){ // 全プロセスがそろった
        if (pthread_cond_broadcast(&barrier_cond) != 0){
            perror("pthread_cond_broadcat");
        exit(-1);
        }
    } else {
        do { // 全プロセスがそろうまで待機
            if (pthread_cond_wait(&barrier_cond,&barrier_mut) !=0){
                perror("pthread_cond_wait");
                exit(-1);
            } 
        } while(*cnt<max); //疑似覚醒のための条件
    }
    
    if (pthread_mutex_unlock(&barrier_mut)!=0){
        perror("pthread_mutex_unlock");
        exit(-1);
    }

}
使用方法は以下のとうり
// barrier main.c
#include "barrier.c"
#include <pthread.h>
#include <stdio.h>

volatile int num = 0;

void *worker(void *arg){
    barrier(&num, 10);
      printf("start!\n");
    return NULL;
}

int main(int argc, char *argv[]){
    pthread_t th[10];
    for (int i=0; i<10; i++) {
        if (pthread_create(&th[i],NULL,worker,NULL)!=0){
            perror("pthread_create");exit(-1);
        }
    }
    for (int i=0; i<10; i++) {
        pthread_join(th[i],NULL);
    }
    return 0;
}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

バリア同期(スピンロック方式) 3.6のサンプルにjoin部を付け足して完成

#include <pthread.h>

#include <stdio.h>

void barrier(volatile int *cnt, int max) { // <1>

    __sync_fetch_and_add(cnt, 1); // <2>

    printf("%d\n", *cnt);

    while (*cnt < max); // <3>

}

volatile int num = 0; // 共有変数

void *worker(void *arg) { // スレッド用関数

    barrier(&num, 10); // 全スレッドがここまで到達するまで待つ <1>

    // 何らかの処理

    printf("here i gotup\n");

    return NULL;

}

int main(int argc, char *argv[]) {

    // スレッド生成

    pthread_t th[10];

    for (int i = 0; i < 10; i++) {

        if (pthread_create(&th[i], NULL, worker, NULL) != 0) {

            perror("pthread_create"); return -1;

        }

    }

    for (int i = 0; i < 10; i++) {

        if (pthread_join(th[i], NULL)) {

            perror("pthread_create"); 

            return -1;

        }

    }

      return 0;

}

cf https://chakku.hatenablog.com/entry/2019/05/30/023649 :: time ./a.out

time コマンドは以下のとおり

https://atmarkit.itmedia.co.jp/ait/articles/1810/25/news022.html

------------------------------------------------------------

RWlock スピンロック方式

#include "../3.3/3_3_1_spinlock_2.c"


// Reader用ロック獲得関数 <1>

void rwlock_read_acquire(int *rcnt, volatile int *wcnt) {

    for (;;) {

        while (*wcnt); // Writerがいるなら待機 <2>

        __sync_fetch_and_add(rcnt, 1); // <3>

        if (*wcnt == 0) // Writerがいない場合にロック獲得 <4>

            break;

        __sync_fetch_and_sub(rcnt, 1);

    }

}


// Reader用ロック解放関数 <5>

void rwlock_read_release(int *rcnt) {

    __sync_fetch_and_sub(rcnt, 1);

}


// Writer用ロック獲得関数 <6>

void rwlock_write_acquire(bool *lock, volatile int *rcnt, int *wcnt) {

    __sync_fetch_and_add(wcnt, 1); // <7>

    while (*rcnt); // Readerがいるなら待機

    spinlock_acquire(lock); // <8>

}


// Writer用ロック解放関数 <9>

void rwlock_write_release(bool *lock, int *wcnt) {

    spinlock_release(lock);

    __sync_fetch_and_sub(wcnt, 1);

}


// 共有変数

int  rcnt = 0;

int  wcnt = 0;

bool lock = false;


void reader() { // Reader用関数

    for (;;) {

        rwlock_read_acquire(&rcnt, &wcnt);

        // クリティカルセクション(読み込みのみ)

        rwlock_read_release(&rcnt);

    }

}


void writer () { // Writer用関数

    for (;;) {

        rwlock_write_acquire(&lock, &rcnt, &wcnt);

        // クリティカルセクション(読み書き)

        rwlock_write_release(&lock, &wcnt);

    }

}

。。。。。。。。。。。。。。。。

0 件のコメント:

コメントを投稿