📜  互斥的彼得森算法设置 2(CPU 周期和内存栅栏)(1)

📅  最后修改于: 2023-12-03 14:49:03.435000             🧑  作者: Mango

互斥的彼得森算法设置 2(CPU 周期和内存栅栏)

简介

彼得森算法是经典的用于解决共享资源互斥访问的算法之一,它是由彼得森(Peterson)于1981年提出的。这种算法通过循环判断和设置标志位来实现多进程之间的互斥访问。

其中,彼得森算法设置2号就是利用了CPU周期的特性和内存栅栏的机制,实现了多进程的互斥访问。

程序实现
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <stdbool.h>

#define N 2

int turn = 0;
bool flag[2] = {false, false};

void* thread_proc(void* arg) {
    int i = *(int*)arg;
    while (true) {
        flag[i] = true;
        turn = 1 - i;
        __sync_synchronize();
        while (flag[1 - i] && turn == 1 - i);
        // 临界区
        printf("Thread %d is in critical section.\n", i);
        // 延时,模拟临界区内的操作
        usleep(1000);
        printf("Thread %d exit critical section.\n", i);
        // 结束临界区
        flag[i] = false;
        usleep(1000);
    }
    return NULL;
}

int main(int argc, char* argv[]) {
    pthread_t threads[N];
    int indexes[N];
    for (int i = 0; i < N; ++i) {
        indexes[i] = i;
        pthread_create(&threads[i], NULL, thread_proc, &indexes[i]);
    }
    for (int i = 0; i < N; ++i) {
        pthread_join(threads[i], NULL);
    }
    return 0;
}
实现原理

当两个进程同时访问临界区时,会产生冲突,为了解决这个问题,彼得森算法设置了一个turn值,即一个标志位,用来标识哪个进程可以访问临界区。

彼得森算法设置2号是通过两个标志位flag[0]和flag[1]来实现的,其中flag[0]和flag[1]分别代表两个进程是否需要访问临界区,当一个进程要访问临界区时,会将自己对应的flag[i]位置为true,同时将turn的值设置为对方进程的编号(即1-i)。

然后,采用内存栅栏的机制来确保所有的写操作都已经刷新到内存中。接着,进入一个while循环,判断另一个进程是否已经在临界区内,如果已经在临界区内,则需要等待;如果没有,则可以进入临界区。完成临界区内的操作后,需要将自己对应的flag[i]位置为false。

总结

彼得森算法是经典的进程同步算法,可以用于解决多进程之间的共享资源互斥访问问题。彼得森算法设置2号利用了CPU周期的特性和内存栅栏的机制,实现了多进程的互斥访问。在实际应用中,我们可以根据实际情况选择不同的解决方案,保证程序的正确性和效率。