Условные переменные и общая память - PullRequest
0 голосов
/ 01 марта 2020

Я пытался использовать условную переменную (с мьютексом) внутри разделяемой памяти для синхронизации родителя и потомка после exe c. Все вроде бы хорошо, ребенок и родитель синхронизированы. Но в случайную точку выполнения я каждый раз получаю сообщение об ошибке «Неверный аргумент» в функции pthread_cond_wait.

Файл test1.c

Код ниже является родительским, который создает переменную mutex, cond (внутри разделяемой памяти) и другой блок разделяемой памяти для данных, а затем попытайтесь поделиться данными с дочерним элементом.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>     

#define PNUM 17500
#define PLENGHT 60
#define MAXLINE 4096


void err_sys(const char *fmt, ...);
void err_exit(int error, const char *fmt, ...);
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap);

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

    /* creating new mutex inside shared memory area */
    void *shmem_mu_ptr;             /* pointer to mutex shared memory */         
    pthread_mutex_t *mu;            /* pointer to mutex */
    int shmem_mu_id;                /* shared memory mutex id */        
    int mu_err;
    size_t size = sizeof(pthread_mutex_t);  /* shared m. mutex size (size was already declared )*/
    char packet[PLENGHT];

    for(int i = 0; i < PLENGHT; i++) packet[i] = 'a';

    /* getting shared m. id for mutex*/
    if ( (shmem_mu_id =  shmget((key_t)1111, size , 0666 | IPC_CREAT )) == -1) err_sys("shared memory error ");

    /* getting shared m. pointer for mutex */
    if ((shmem_mu_ptr = shmat(shmem_mu_id, 0, 0)) == (void *)-1) err_sys("shmat error");

    /* make mu, that expects a memory area made like pthread_mutex_t , to point the shared memory. */
    mu = (pthread_mutex_t *)shmem_mu_ptr;

    /* initialize the attribute to prepare mutex to be placed in shared memory */
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);

    /* initialize mutex */
    pthread_mutex_init(mu,&attr);
    pthread_mutexattr_destroy(&attr);


    /* creating new condition variable inside shared memory area */
    void *shmem_cond_ptr;           /* pointer to cond shared memory */
    int shmem_cond_id;              /* shared memory cond id */     
    pthread_cond_t *cond;
    size = sizeof(pthread_cond_t);  /* shared m. cond size (size was already declared )*/

    /* getting shared m. id for cond*/
    if ( (shmem_cond_id =  shmget((key_t)2222, size , 0666 | IPC_CREAT )) == -1) err_sys("shared memory error ");

    /* getting shared m. pointer for cond */
    if ((shmem_cond_ptr = shmat(shmem_cond_id, 0, 0)) == (void *)-1) err_sys("shmat error");

    /* make cond, that expects a memory area made like pthread_cond_t , to point the shared memory. */
    cond = (pthread_cond_t *)shmem_cond_ptr;


    /* * initialize the attribute to prepare cond to be placed in shared memory */
    pthread_condattr_t attrcond;
    pthread_condattr_init(&attrcond);
    pthread_condattr_setpshared(&attrcond, PTHREAD_PROCESS_SHARED);

    /* Initialize condition. */
    pthread_cond_init(cond, &attrcond);
    pthread_condattr_destroy(&attrcond);

    /* Clean up. */
    pthread_condattr_destroy(&attrcond); 


    /* creating new shared memory area to share only PLENGHT (60) byte at time */
    void *shmem_ptr60;
    int shmem60;
    char *shmem_char;
    size = sizeof(char) * PLENGHT;   /* shared m. data size (size was already declared )*/

    /* getting shared m. id */
    if ( (shmem60 =  shmget(3333, size , 0666 | IPC_CREAT )) == -1) err_sys("shared memory error ");

    /* getting shared m. pointer */
    if ((shmem_ptr60 = shmat(shmem60, 0, 0)) == (void *)-1) err_sys("shmat error");

    shmem_char = shmem_ptr60;

    /* locking mutex before creating new process to avoid child reading void memory area */
    if( (mu_err = pthread_mutex_lock(mu)) != 0 ) err_exit(mu_err,"lock mutex error");

    /* calling child */
    pid_t pid;
    if( (pid = vfork()) == -1 )err_sys("fork error");
    else if(pid == 0){
        if (execl("./test2","test2",(void*)0) == -1) err_sys("exec error");
        exit(0);
    }
    else if (pid == -1 ) err_sys("fork error");


    /*  copying data inside shared memory */
    for( int i = 0; i < PNUM; i++){
        strcpy(shmem_char, packet);
        printf("data written, iteration number :%d\n",i);
        if ( (mu_err = pthread_cond_signal(cond)) != 0) err_exit(mu_err,"cond signal error: ");
        if ( (mu_err = pthread_cond_wait(cond, mu)) != 0) err_exit(mu_err,"cond wait error"); 
    }
    if ( (mu_err = pthread_mutex_unlock(mu)) != 0) err_exit(mu_err,"mutex unlock error");

    waitpid(pid,NULL,(int)NULL);

    if (shmctl(shmem_mu_id, IPC_RMID, 0) < 0) err_sys("shmctl error");
    if (shmctl(shmem_cond_id, IPC_RMID, 0) < 0) err_sys("shmctl error");
    if (shmctl(shmem60, IPC_RMID, 0) < 0) err_sys("shmctl error");

    return 0;
}


/* from apue to print errors*/
void err_sys(const char *fmt, ...){
    va_list     ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}

void err_exit(int error, const char *fmt, ...){
    va_list     ap;

    va_start(ap, fmt);
    err_doit(1, error, fmt, ap);
    va_end(ap);
    exit(1);
}

static void err_doit(int errnoflag, int error, const char *fmt, va_list ap){
    char    buf[MAXLINE];

    vsnprintf(buf, MAXLINE-1, fmt, ap);
    if (errnoflag)
        snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s",
          strerror(error));
    strcat(buf, "\n");
    fflush(stdout);     /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL);       /* flushes all stdio output streams */
}

Файл test2.c

Затем дочерний элемент восстанавливает всю разделяемую память области, содержащие мьютекс, переменную условия и данные, и попробуйте прочитать. Код ниже является дочерним.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h> 

#define PNUM 17500  
#define MAXLINE 4096
#define PLENGHT 60


void err_sys(const char *fmt, ...);
void err_exit(int error, const char *fmt, ...);
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap);



int main (int argc , char *argv[]){
    char packets[PNUM][PLENGHT];


    /* -----recovering mutex inside shared memory */
    pthread_mutex_t *mu;
    int shmem_mu_id;
    void* shmem_mu_ptr;
    int mu_err;

    /* getting shared m. id for data*/
    if ( (shmem_mu_id =  shmget((key_t)1111, 0 , 0666 | IPC_CREAT )) == -1) err_sys("shared memory error ");

    /* getting shared m. pointer for data */
    if ((shmem_mu_ptr = shmat(shmem_mu_id, 0, 0)) == (void *)-1) err_sys("shmat error");

    /* make mu, that expects a memory area made like pthread_mutex_t *, to point the shared memory. */
    mu = (pthread_mutex_t *)shmem_mu_ptr;


    /* -----recovering condition variable inside shared memory */
    void *shmem_cond_ptr;           /* pointer to cond shared memory */
    int shmem_cond_id;              /* shared memory cond id */     
    pthread_cond_t *cond;

    /* getting shared m. id for cond*/
    if ( (shmem_cond_id =  shmget((key_t)2222, 0 , 0666 | IPC_CREAT )) == -1) err_sys("shared memory error ");

    /* getting shared m. pointer for cond */
    if ((shmem_cond_ptr = shmat(shmem_cond_id, 0, 0)) == (void *)-1) err_sys("shmat error");

    /* make cond, that expects a memory area made like pthread_cond_t , to point the shared memory. */
    cond = (pthread_cond_t *)shmem_cond_ptr;

    /* recovering shared memory aread with data */
    int shmem;
    char *shmem_ptr;

    if ( (shmem =  shmget(3333, 0, 0666 )) == -1) err_sys("shared memory error ");
    if ((shmem_ptr = shmat(shmem, 0, 0)) == (void *)-1) err_sys("shmat error child");


    if( (mu_err = pthread_mutex_lock(mu)) != 0 ) err_exit(mu_err,"lock mutex error");

    /* try to read data inside shared memory */
    for (int i = 0; i < PNUM; i++){ 
        strcpy(packets[i],shmem_ptr);
        printf("data read, iteration number :%d\n",i);
        if ( (mu_err = pthread_cond_signal(cond)) != 0) err_exit(mu_err,"cond signal error: ");
        if ( (mu_err = pthread_cond_wait(cond, mu)) != 0) err_exit(mu_err,"cond wait error"); 

    }

    if ( (mu_err = pthread_mutex_unlock(mu)) != 0) err_exit(mu_err,"mutex unlock error");
    return 0;

}




/* from apue to print errors*/
void err_sys(const char *fmt, ...){
    va_list     ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}

void err_exit(int error, const char *fmt, ...){
    va_list     ap;

    va_start(ap, fmt);
    err_doit(1, error, fmt, ap);
    va_end(ap);
    exit(1);
}

static void err_doit(int errnoflag, int error, const char *fmt, va_list ap){
    char    buf[MAXLINE];

    vsnprintf(buf, MAXLINE-1, fmt, ap);
    if (errnoflag)
        snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s",
          strerror(error));
    strcat(buf, "\n");
    fflush(stdout);     /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL);       /* flushes all stdio output streams */
}

Проблема появляется внутри для l oop в родительском элементе: pthread_cond_wait после сбоя случайного числа итераций с ошибкой неверного аргумента.

Это вывод:

[...]
data written, iteration number :85
data read, iteration number :85
data written, iteration number :86
data read, iteration number :86
data written, iteration number :87
data read, iteration number :87
data written, iteration number :88
data read, iteration number :88
data written, iteration number :89
data read, iteration number :89
data written, iteration number :90
data read, iteration number :90
cond wait error: Invalid argument

Страница руководства по функции pthread_cond_wait сообщает:

Эти функции атомарно освобождают мьютекс и заставляют вызывающий поток блокировать переменную условия cond; «атомно» здесь означает «атомарно в отношении доступа другого потока к мьютексу и затем к условной переменной».

Я работаю с процессами, а не с потоками: это может объяснить проблему или я сделал ошибку?

1 Ответ

2 голосов
/ 01 марта 2020

У вас есть неограниченное переполнение буфера, потому что вы не завершаете строку нулем. У вас есть:

char packet[PLENGHT];

for(int i = 0; i < PLENGHT; i++) packet[i] = 'a';

…lots of lines…

strcpy(shmem_char, packet);

Копирование не-строки с strcpy() не очень хорошая идея - у вас переполнение буфера. Я добавил:

packet[PLENGHT - 1] = '\0';

и все, казалось, работало.

Я добавил некоторую информацию о диагностике c и получил:

data written, iteration number :17499
data read, iteration number: 17499 [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]

Затем программы зависли - Мне пришлось их прервать.

Обратите внимание, что PLENGTH было бы более нормальным написанием для длины.

Исправленный код test1.c

Я уменьшил число итераций до 25 (с 17500). Я исправил различные вещи и решил использовать свой собственный код сообщения об ошибках, который доступен в моем репозитории SOQ (вопросы о переполнении стека) на GitHub в виде файлов stderr.c и stderr.h в * 1025 Подкаталог * src / libsoq . Мне нужно было знать, какая программа генерирует ошибку; Я получил информацию (это было test1), используя эти функции. Я не тратил время на модернизацию кода в test2.c. Я добавил дополнительные pthread_cond_signal() после основного l oop в test1.c; теперь ребенок выходит, поэтому родитель выходит - и все в порядке. Все вызовы pthread_* проверены на ошибки. Код изменяет сообщение до его отправки, чтобы вы могли определить, правильно ли ребенок забирает сообщение. Сообщение печатается до его отправки и после прочтения.

Основное исправление ошибки - добавление;

    packet[PLENGTH - 1] = '\0';

Это гарантирует, что пакет содержит строку, а не только полный буфер байтов.

#include "stderr.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>

//#define PNUM 17500
#define PNUM 25
#define PLENGTH 60
#define MAXLINE 4096

int main(int argc, char **argv)
{
    if (argc > 0)
        err_setarg0(argv[0]);
    /* creating new mutex inside shared memory area */
    void *shmem_mu_ptr;             /* pointer to mutex shared memory */
    pthread_mutex_t *mu;            /* pointer to mutex */
    int shmem_mu_id;                /* shared memory mutex id */
    int mu_err;
    size_t size = sizeof(pthread_mutex_t);  /* shared m. mutex size (size was already declared) */
    char packet[PLENGTH];

    for (int i = 0; i < PLENGTH; i++)
        packet[i] = 'a';
    packet[PLENGTH - 1] = '\0';

    /* getting shared m. id for mutex*/
    if ((shmem_mu_id =  shmget((key_t)1111, size, 0666 | IPC_CREAT)) == -1)
        err_syserr("shared memory error ");

    /* getting shared m. pointer for mutex */
    if ((shmem_mu_ptr = shmat(shmem_mu_id, 0, 0)) == (void *)-1)
        err_syserr("shmat error: ");

    /* make mu, that expects a memory area made like pthread_mutex_t , to point the shared memory. */
    mu = (pthread_mutex_t *)shmem_mu_ptr;

    /* initialize the attribute to prepare mutex to be placed in shared memory */
    int rc;
    pthread_mutexattr_t attr;
    if ((rc = pthread_mutexattr_init(&attr)) != 0)
        err_syserror(rc, "pthread_mutexattr_init: ");
    if ((rc = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) != 0)
        err_syserror(rc, "pthread_mutexattr_setpshared: ");

    /* initialize mutex */
    if ((rc = pthread_mutex_init(mu, &attr)) != 0)
        err_syserror(rc, "pthread_mutex_init: ");
    if ((rc = pthread_mutexattr_destroy(&attr)) != 0)
        err_syserror(rc, "pthread_mutexattr_destroy: ");

    /* creating new condition variable inside shared memory area */
    void *shmem_cond_ptr;           /* pointer to cond shared memory */
    int shmem_cond_id;              /* shared memory cond id */
    pthread_cond_t *cond;
    size = sizeof(pthread_cond_t);  /* shared m. cond size (size was already declared) */

    /* getting shared m. id for cond*/
    if ((shmem_cond_id =  shmget((key_t)2222, size, 0666 | IPC_CREAT)) == -1)
        err_syserr("shared memory error ");

    /* getting shared m. pointer for cond */
    if ((shmem_cond_ptr = shmat(shmem_cond_id, 0, 0)) == (void *)-1)
        err_syserr("shmat error: ");

    /* make cond, that expects a memory area made like pthread_cond_t , to point the shared memory. */
    cond = (pthread_cond_t *)shmem_cond_ptr;

    /* * initialize the attribute to prepare cond to be placed in shared memory */
    pthread_condattr_t attrcond;
    if ((rc = pthread_condattr_init(&attrcond)) != 0)
        err_syserror(rc, "pthread_condattr_init: ");
    if ((rc = pthread_condattr_setpshared(&attrcond, PTHREAD_PROCESS_SHARED)) != 0)
        err_syserror(rc, "pthread_condattr_setpshared: ");

    /* Initialize condition. */
    if ((rc = pthread_cond_init(cond, &attrcond)) != 0)
        err_syserror(rc, "pthread_cond_init: ");
    if ((rc = pthread_condattr_destroy(&attrcond)) != 0)
        err_syserror(rc, "pthread_condattr_destroy: ");

    /* Clean up. */
    //pthread_condattr_destroy(&attrcond);

    /* creating new shared memory area to share only PLENGTH (60) byte at time */
    void *shmem_ptr60;
    int shmem60;
    char *shmem_char;
    size = sizeof(char) * PLENGTH;   /* shared m. data size (size was already declared) */

    /* getting shared m. id */
    if ((shmem60 = shmget(3333, size, 0666 | IPC_CREAT)) == -1)
        err_syserr("shared memory error ");

    /* getting shared m. pointer */
    if ((shmem_ptr60 = shmat(shmem60, 0, 0)) == (void *)-1)
        err_syserr("shmat error: ");

    shmem_char = shmem_ptr60;

    /* locking mutex before creating new process to avoid child reading void memory area */
    if ((mu_err = pthread_mutex_lock(mu)) != 0)
        err_syserror(mu_err, "lock mutex error: ");

    /* calling child */
    pid_t pid;
    //if ((pid = vfork()) == -1)
    if ((pid = fork()) == -1)
        err_syserr("fork error: ");
    else if (pid == 0)
    {
        if (execl("./test2", "test2", (void *)0) == -1)
            err_syserr("exec error: ");
        exit(0);
    }
    //else if (pid == -1)
        //err_syserr("fork error: ");
    printf("Child forked OK\n");

    /*  copying data inside shared memory */
    for (int i = 0; i < PNUM; i++)
    {
        packet[i % (PLENGTH - 1)]++;
        strcpy(shmem_char, packet);
        printf("data written, iteration number: %d [%s]\n", i, packet);
        if ((mu_err = pthread_cond_signal(cond)) != 0)
            err_syserror(mu_err, "pthread_cond_signal: ");
        if ((mu_err = pthread_cond_wait(cond, mu)) != 0)
            err_syserror(mu_err, "pthread_cond_wait: ");
    }
    if ((mu_err = pthread_cond_signal(cond)) != 0)
        err_syserror(mu_err, "pthread_cond_signal: ");
    if ((mu_err = pthread_mutex_unlock(mu)) != 0)
        err_syserror(mu_err, "pthread_mutex_unlock: ");

    waitpid(pid, NULL, 0);

    if (shmctl(shmem_mu_id, IPC_RMID, 0) < 0)
        err_syserr("shmctl error: ");
    if (shmctl(shmem_cond_id, IPC_RMID, 0) < 0)
        err_syserr("shmctl error: ");
    if (shmctl(shmem60, IPC_RMID, 0) < 0)
        err_syserr("shmctl error: ");

    return 0;
}

Пересмотренный код test2.c

Как правило, это значительно менее сильно отредактировано.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>

//#define PNUM 17500
#define PNUM 25
#define MAXLINE 4096
#define PLENGTH 60

void err_sys(const char *fmt, ...);
void err_exit(int error, const char *fmt, ...);
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap);

int main(void)
{
    char packets[PNUM][PLENGTH];

    /* -----recovering mutex inside shared memory */
    pthread_mutex_t *mu;
    int shmem_mu_id;
    void *shmem_mu_ptr;
    int mu_err;

    /* getting shared m. id for data*/
    if ((shmem_mu_id =  shmget((key_t)1111, 0, 0666 | IPC_CREAT)) == -1)
        err_sys("shared memory error ");

    /* getting shared m. pointer for data */
    if ((shmem_mu_ptr = shmat(shmem_mu_id, 0, 0)) == (void *)-1)
        err_sys("shmat error");

    /* make mu, that expects a memory area made like pthread_mutex_t *, to point the shared memory. */
    mu = (pthread_mutex_t *)shmem_mu_ptr;

    printf("mutex recovered\n");

    /* -----recovering condition variable inside shared memory */
    void *shmem_cond_ptr;           /* pointer to cond shared memory */
    int shmem_cond_id;              /* shared memory cond id */
    pthread_cond_t *cond;

    /* getting shared m. id for cond*/
    if ((shmem_cond_id =  shmget((key_t)2222, 0, 0666 | IPC_CREAT)) == -1)
        err_sys("shared memory error ");

    /* getting shared m. pointer for cond */
    if ((shmem_cond_ptr = shmat(shmem_cond_id, 0, 0)) == (void *)-1)
        err_sys("shmat error");

    /* make cond, that expects a memory area made like pthread_cond_t , to point the shared memory. */
    cond = (pthread_cond_t *)shmem_cond_ptr;
    printf("condition recovered\n");

    /* recovering shared memory read with data */
    int shmem;
    char *shmem_ptr;

    if ((shmem = shmget(3333, 0, 0666)) == -1)
        err_sys("shared memory error ");
    if ((shmem_ptr = shmat(shmem, 0, 0)) == (void *)-1)
        err_sys("shmat error child");
    printf("data memory recovered\n");

    if ((mu_err = pthread_mutex_lock(mu)) != 0)
        err_exit(mu_err, "lock mutex error");

    /* try to read data inside shared memory */
    for (int i = 0; i < PNUM; i++)
    {
        strcpy(packets[i], shmem_ptr);
        printf("data read, iteration number: %d [%s]\n", i, packets[i]);
        if ((mu_err = pthread_cond_signal(cond)) != 0)
            err_exit(mu_err, "cond signal error: ");
        if ((mu_err = pthread_cond_wait(cond, mu)) != 0)
            err_exit(mu_err, "cond wait error");
    }

    if ((mu_err = pthread_mutex_unlock(mu)) != 0)
        err_exit(mu_err, "mutex unlock error");
    return 0;
}

/* from apue to print errors*/
void err_sys(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}

void err_exit(int error, const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    err_doit(1, error, fmt, ap);
    va_end(ap);
    exit(1);
}

static void err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
    char buf[MAXLINE];

    vsnprintf(buf, MAXLINE - 1, fmt, ap);
    if (errnoflag)
        snprintf(buf + strlen(buf), MAXLINE - strlen(buf) - 1, ": %s",
                 strerror(error));
    strcat(buf, "\n");
    fflush(stdout);     /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL);       /* flushes all stdio output streams */
}

Пример вывода

$ ./test1
Child forked OK
data written, iteration number: 0 [baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
mutex recovered
condition recovered
data memory recovered
data read, iteration number: 0 [baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 1 [bbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 1 [bbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 2 [bbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 2 [bbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 3 [bbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 3 [bbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 4 [bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 4 [bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 5 [bbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 5 [bbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 6 [bbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 6 [bbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 7 [bbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 7 [bbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 8 [bbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 8 [bbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 9 [bbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 9 [bbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 10 [bbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 10 [bbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 11 [bbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 11 [bbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 12 [bbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 12 [bbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 13 [bbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 13 [bbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 14 [bbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 14 [bbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 15 [bbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 15 [bbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 16 [bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 16 [bbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 17 [bbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 17 [bbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 18 [bbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 18 [bbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 19 [bbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 19 [bbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 20 [bbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 20 [bbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 21 [bbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 21 [bbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 22 [bbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 22 [bbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 23 [bbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 23 [bbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data written, iteration number: 24 [bbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
data read, iteration number: 24 [bbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
$

Тестовая среда

Я использую MacBook Pro с MacOS Catalina 10.15.3 и использую G CC 9.2.0 (который я сам скомпилировал) и Xcode 11.3.1 для всего, что формально не является частью G CC.

Любопытное наблюдение: у меня, похоже, нет справочной страницы для pthread_mutexattr_setpshared() или pthread_condattr_setpshared(), но обе функции обнаруживаются при компоновке (и компиляции) и, похоже, работают нормально.

...