屏障的作用是允许每个线程完成自身任务之后等待,直到所有线程都达到某一点,然后从该点继续执行。

默认情况下屏障应用于单个进程的多个线程之间。

屏障的进程共享属性允许将屏障应用于多个进程之间,前提是多个进程能够访问到同一个屏障对象。

属性介绍

数据类型:pthread_barrierattr_t

初始化与反初始化函数:

#include <pthread.h>

int pthread_barrierattr_destroy(pthread_barrierattr_t* attr);
int pthread_barrierattr_init(pthread_barrierattr_t* attr);
// 返回值:成功返回0,失败返回错误编号

pthread_barrierattr_init()函数将屏障属性初始化为默认值。

进程共享属性

作用:该进程共享属性控制着屏障是可以被多进程的线程使用,还是只能被初始化屏障的进程内的多线程使用。

取值:PTHREAD_PROCESS_SHAREDPTHREAD_PROCESS_PRIVATE

获取与设置函数:

#include <pthread.h>

int pthread_barrierattr_getpshared(const pthread_barrierattr_t* restrict attr, int* restrict pshared);
int pthread_barrierattr_setpshared(pthread_barrierattr_t* attr, int pshared);
// 返回值:成功返回0,失败返回错误编号

示例

下面的示例主要有ChatGPT3.5来生成,并在此基础上做了一点修改。

示例中,在5个进程中使用屏障的进程共享属性。

屏障在初始化时,如果屏障计数大于pthread_barrier_wait()函数的调用次数并且屏障没有被销毁,那么会启动第二次屏障阻塞,以等待再次同步。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define NUM_PROCESSES 5

pthread_barrier_t* barrier;

void* threadFunction(void* arg)
{
    int processId = *(int*)arg;
    printf("Process %d: Hello!\n", processId);
    printf("Process %d: Goodbye!\n", processId);
    pthread_barrier_wait(barrier);
    printf("Process %d: barrier finish\n", processId);
    return NULL;
}

int main()
{
    pid_t processIds[NUM_PROCESSES];

    // 创建共享内存
    barrier = mmap(NULL, sizeof(pthread_barrier_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    // 初始化屏障
    pthread_barrierattr_t attr;
    pthread_barrierattr_init(&attr);
    pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
    // 如果不加1,会导致有个进程无法退出,因为到达屏障计数后,屏障会重新计数,直到再次到达屏障计数
    pthread_barrier_init(barrier, &attr, NUM_PROCESSES + 1);
    pthread_barrierattr_destroy(&attr);

    // 创建子进程
    for (int i = 0; i < NUM_PROCESSES; i++)
    {
        processIds[i] = fork();
        if (processIds[i] == 0)
        {
            int processId = i + 1;
            pthread_t thread;
            pthread_create(&thread, NULL, threadFunction, &processId);
            pthread_join(thread, NULL);
            exit(0);
        }
    }

    pthread_barrier_wait(barrier);
    printf("Main Process: barrier wait finish\n");
    // 等待子进程结束
    for (int i = 0; i < NUM_PROCESSES; i++)
        waitpid(processIds[i], NULL, 0);

    // 销毁屏障
    pthread_barrier_destroy(barrier);
    // 释放共享内存
    munmap(barrier, sizeof(pthread_barrier_t));
    return 0;
}
// Process 1: Hello!
// Process 1: Goodbye!
// Process 2: Hello!
// Process 2: Goodbye!
// Process 3: Hello!
// Process 3: Goodbye!
// Process 5: Hello!
// Process 5: Goodbye!
// Process 4: Hello!
// Process 4: Goodbye!
// Process 1: barrier finish
// Process 2: barrier finish
// Process 4: barrier finish
// Main Process: barrier wait finish
// Process 5: barrier finish
// Process 3: barrier finish