我的peterson_lock在这种情况下失败了

时间:2017-04-14 06:23:04

标签: c++

代码:
[peterson_lock.h]

#include <pthread.h>

typedef struct {
    volatile bool flag[2];
    volatile int victim;
} peterson_lock_t;

void peterson_lock_init(peterson_lock_t &lock) {
    lock.flag[0] = lock.flag[1] = false;
    lock.victim = 0;
}

void peterson_lock(peterson_lock_t &lock, int id) {
    lock.victim = id; // Mark as A
    lock.flag[id] = true; // Mark as B
    asm volatile ("mfence" : : : "memory");
    while (lock.flag[1 - id] && lock.victim == id);
}

void peterson_unlock(peterson_lock_t &lock, int id) {
    lock.flag[id] = false;
    lock.victim = id;
}

[main.cpp中]

#include <stdio.h>
#include "peterson_lock.h"

peterson_lock_t lock;
int count = 0;

void *routine0(void *arg) {
    int *cnt = (int *)arg;
    for (int i = 0; i < *cnt; ++i) {
        peterson_lock(lock, 0);
        ++count;
        peterson_unlock(lock, 0);
    }

    return NULL;
}

void *routine1(void *arg) {
    int *cnt = (int *)arg;
    for (int i = 0; i < *cnt; ++i) {
        peterson_lock(lock, 1);
        ++count;
        peterson_unlock(lock, 1);
    }
}

int main(int argc, char **argv) {
    peterson_lock_init(lock);
    pthread_t thread0, thread1;
    int count0 = 10000;
    int count1 = 20000;
    pthread_create(&thread0, NULL, routine0, (void *)&count0);
    pthread_create(&thread1, NULL, routine1, (void *)&count1);

    pthread_join(thread0, NULL);
    pthread_join(thread1, NULL);

    printf("Expected: %d\n", (count0 + count1));
    printf("Reality : %d\n", count);

    return 0;
}

运行此程序1000次,有时结果不是30000。但是,如果我切换AB,结果始终为30000。但这怎么可能发生呢?

[请忽略这一行,只是为了让这个问题可以提交。请忽略这一行,只是为了让这个问题可以提交。请忽略这一行,只是为了让这个问题可以提交。]

1 个答案:

答案 0 :(得分:0)

该算法要求您更换A和B.换句话说,您发布的代码并不是Peterson算法的正确实现。

让我们看看出了什么问题。

首先使用此代码:

void peterson_lock(peterson_lock_t &lock, int id) {
    lock.victim = id; // Mark as A
    lock.flag[id] = true; // Mark as B
    asm volatile ("mfence" : : : "memory");
    while (lock.flag[1 - id] && lock.victim == id);
}

并将其作为每个进程的函数写入:

void peterson_lock_0(peterson_lock_t &lock) {
    lock.victim = 0;
    lock.flag[0] = true;
    asm volatile ("mfence" : : : "memory");
    while (lock.flag[1] && lock.victim == 0);
}

void peterson_lock_1(peterson_lock_t &lock) {
    lock.victim = 1;
    lock.flag[1] = true;
    asm volatile ("mfence" : : : "memory");
    while (lock.flag[0] && lock.victim == 1);
}

然后让进程0执行第一行,然后切换到进程1(执行整个函数),然后再回到进程0。

peterson_lock_0:                       peterson_lock_1:
-------------------------------------------------------
lock.victim = 0;
                                      lock.victim = 1;
                                      lock.flag[1] = true;
                                      asm volatile ("mfence" : : : "memory");
                                      while (lock.flag[0] && lock.victim == 1);
                                      // lock.flag[0] is false so
                                      // the process enters critical
                                      // section
lock.flag[0] = true;
asm volatile ("mfence" : : : "memory");
while (lock.flag[1] && lock.victim == 0);
// lock.victim is 1 so
// the process enters critical
// section

现在两个流程都处于关键部分。那太糟糕了。

有关详细信息,请参阅https://en.wikipedia.org/wiki/Peterson%27s_algorithm