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);
}
}
。。。。。。。。。。。。。。。。