彼得森算法的错误实现?

时间:2012-02-25 10:58:59

标签: c posix parallel-processing

我试图了解并行编程的一些内容,所以我尝试实现Peterson的算法,这是一个简单的例子,其中一个共享计数器增加2个线程。我知道彼得森因等待的忙而不是最佳的,但我只是出于学习原因尝试过。

我认为此代码的关键部分位于线程函数add中,其中共享counter递增。所以我在计数器递增之前调用enter_section函数,之后调用leave_function。这部分错了吗?我评估了关键部分错了吗?问题是当这两个线程完成时,计数器有时会给出一个不可预见的值。它必须是线程之间的同步问题,但我只是看不到它......感谢您的帮助。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int counter; /* global shared counter */
int flag[2] = {0, 0}; /* Variables for Peterson's algorithm */
int turn = 0;

typedef struct threadArgs 
{
    pthread_t thr_ID;
    int num_of_repeats;
    int id;
} THREADARGS;

void enter_section (int thread) {
    int other = 1 - thread;

    flag[thread] = 1;
    turn = thread;

    while ((turn == thread) && (flag[other] == 1));

    return;
}

void leave_section (int thread) {
    flag[thread] = 0;

    return;
}


void * add (void * arg) {

    int i;
    THREADARGS * a = (THREADARGS *) arg;

    for (i = 0; i < a->num_of_repeats; i++) {
        enter_section(a->id);
        counter++;
        leave_section(a->id);
    }

    return NULL;
}

int main () {
    int i = 1;
    pthread_attr_t thrAttr;
    THREADARGS threadargs_array[2];

    pthread_attr_init (&thrAttr);
    pthread_attr_setdetachstate (&thrAttr, PTHREAD_CREATE_JOINABLE);

    /* creating 1st thread */

    threadargs_array[0].id = 0;
    threadargs_array[0].num_of_repeats = 1000000;

    pthread_create(&threadargs_array[0].thr_ID, &thrAttr, add, &threadargs_array[0]);

    /* creating 2nd thread */

    threadargs_array[1].id = 1;
    threadargs_array[1].num_of_repeats = 2000000;

    pthread_create(&threadargs_array[1].thr_ID, &thrAttr, add, &threadargs_array[1]);

    /* free resources for thread attributes */
    pthread_attr_destroy (&thrAttr);

    /* waiting for 1st thread */
    pthread_join (threadargs_array[0].thr_ID, NULL);
    printf("First thread is done.\n");

    /* waiting for 2nd thread */
    pthread_join (threadargs_array[1].thr_ID, NULL);
    printf("Second thread is done.\n");


    printf("Counter value is: %d \n", counter);
    return (EXIT_SUCCESS);
}

1 个答案:

答案 0 :(得分:4)

这里有几个问题:

  • 我们会对您的变量进行优化,因此您必须至少声明它们volatile
  • 这样的算法在没有POSIX提供的任何锁定数据结构的线程之间访问数据只能在原始操作保证是原子的情况下才能工作,而它们通常不在现代处理器上。特别是++运算符原子。

有很多方法可以解决这个问题,特别是新的C标准C11提供了原子基元。但是,如果这对你来说真的是一个学习并行编程的开始,我强烈建议你先研究互斥,条件变量等,以了解POSIX的工作原理。