C++ セマフォ動作確認

C++のセマフォの値の増減が行われているか
確認するためのプログラム

## wait
while(1)でループ
「end」と入力されるまで終わらない。
また、wait...[]←この部分にセマフォの値を表示した。
3つpostしても2の表示になるのは、
1つ目は、waitから復帰して動くためである

```c++:sem_wait.cpp
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>

#define SEMNAME "/sem"
#define STRNAME "/string"
#define MAX 1024

// sem開放
void sem_free(sem_t *sem){
    // semaphore解放
    sem_destroy( sem );

    // 共有メモリ開放
    shm_unlink(SEMNAME);
}

// str開放
void str_free(char *str){
    // 共有メモリ開放
    shm_unlink(STRNAME);
}

int main()
{
    int p_id;
    int status;
    int return_code = 0;
    int i;

    int fd_sem;
    void *ptr_sem;
    int sem_num;
    int fd_str;
    void *ptr_str;
    struct stat stat;

    // semの共有メモリ作成
    fd_sem = shm_open(SEMNAME, O_CREAT | O_RDWR, 0666);
    ftruncate(fd_sem, MAX);

    // semの共有メモリをポインタに割り当てる
    ptr_sem = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_sem, 0);
    
    // strの共有メモリ作成
    fd_str = shm_open(STRNAME, O_CREAT | O_RDWR, 0666);
    ftruncate(fd_str, MAX);

    // strの共有メモリをポインタに割り当てる
    ptr_str = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_str, 0);

    // semのポインタのアドレスをsemに割り当てる
    sem_t *sem = (sem_t*)ptr_sem;

    // strのポインタのアドレスをstrに割り当てる
    char *str = (char*)ptr_str;

    // sempahoreの初期化:プロセス間を可能でsemの値0から
    if (sem_init( sem, 1, 0 ) < 0) {
        perror("init");
        sem_free(sem);
        exit(EXIT_FAILURE);
    }

    strcpy(str,"Initial");
    cout << str << endl;

    while(1){
        sem_getvalue(sem, &sem_num);
        cout << "wait...[" << sem_num << "]" << endl;
        if(sem_wait(sem) < 0){ // waitする
            perror("wait");
            sem_free(sem);
            exit(EXIT_FAILURE);
        }
        if(strcmp(str, "end\n") == 0){
            break;
        }
        cout << "> " << str;
        sleep(1);
    }
    cout << "end" << endl;

    if (sem_post(sem) < 0) { // postする
        perror("post");
        sem_free(sem);
        exit(EXIT_FAILURE);
    }

    sem_free(sem);
    str_free(str);
    return return_code;
}
```

## post
post側でもwhile(1)のループ処理で
「end」の入力が来るまで終わらない。
セマフォの挙動を確認するために
一度文字列を書いた後、3回postするので
wait側は、3回同じ文字列が表示される

```c++:sem_post.cpp
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>

#define SEMNAME "/sem"
#define STRNAME "/string"

// sem開放
void sem_free(sem_t *sem){
    // semaphore解放
    sem_destroy( sem );

    // 共有メモリ開放
    shm_unlink(SEMNAME);
}

// str開放
void str_free(char *str){
    // 共有メモリ開放
    shm_unlink(STRNAME);
}

int main()
{
    int p_id;
    int status;
    int return_code = 0;
    int i;

    int fd_sem;
    void *ptr_sem;
    int sem_num;
    int fd_str;
    void *ptr_str;
    struct stat stat;

    // semの共有メモリ作成
    fd_sem = shm_open(SEMNAME, O_CREAT | O_RDWR, 0666);
    ftruncate(fd_sem, 1024);

    // semの共有メモリをポインタに割り当てる
    ptr_sem = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_sem, 0);
    
    // strの共有メモリ作成
    fd_str = shm_open(STRNAME, O_CREAT | O_RDWR, 0666);
    ftruncate(fd_str, 1024);

    // strの共有メモリをポインタに割り当てる
    ptr_str = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_str, 0);

    // semのポインタのアドレスをsemに割り当てる
    sem_t *sem = (sem_t*)ptr_sem;

    // strのポインタのアドレスをstrに割り当てる
    char *str = (char*)ptr_str;

    // sempahoreの初期化:プロセス間を可能でsemの値0から
    if (sem_init( sem, 1, 0 ) < 0) {
        perror("init");
        sem_free(sem);
        exit(EXIT_FAILURE);
    }

    strcpy(str,"Initial");
    cout << str << endl;

    while(1){
        sem_getvalue(sem, &sem_num);
        cout << "wait...[" << sem_num << "]" << endl;
        if(sem_wait(sem) < 0){ // waitする
            perror("wait");
            sem_free(sem);
            exit(EXIT_FAILURE);
        }
        if(strcmp(str, "end\n") == 0){
            break;
        }
        cout << "> " << str;
        sleep(1);
    }
    cout << "end" << endl;

    if (sem_post(sem) < 0) { // postする
        perror("post");
        sem_free(sem);
        exit(EXIT_FAILURE);
    }

    sem_free(sem);
    str_free(str);
    return return_code;
}
```

## 実行結果
コンパイル
`❯ g++ sem_wait2.cpp -pthread -lrt -o w.o`
`❯ g++ sem_post2.cpp -pthread -lrt -o p.o`

wait側の結果

```zsh
❯ ./w.o
Initial
wait...[0]
> aaaaa
wait...[2]
> aaaaa
wait...[1]
> aaaaa
wait...[0]
end
```

post側の結果

```zsh
❯ ./p.o
str input please...
> aaaaa
str input please...
> end
post done.

```