【问题标题】:Peterson's Algorithm's behavior for various optimization flags彼得森算法对各种优化标志的行为
【发布时间】:2012-07-24 08:23:40
【问题描述】:

我想检查 gcc 和 icc 的行为以了解各种优化选项。 采用了 Peterson 的 2 Thread mutex 算法。如果 lock 方法中 line a 和 line b(以 cmets 为单位)的执行顺序被交换,则此算法可能会失败。 使用带有 -O0 标志的 icc 或 gcc 进行编译会产生正确的结果。 使用带有 -O3 标志的 icc 进行编译会产生不正确的结果。 使用带有 -O3 标志的 gcc 进行编译不会产生任何结果。程序挂起。 所以我的猜测是使用 -O3 标志 gcc 和 icc 都优化了 lock 方法并假设 line a 和 line b 之间没有依赖关系。因此,两者都产生了错误的结果。 这样的依赖对于编译器来说很难找到,那么有没有办法(像 ivdep 这样的编译指示)告诉编译器特定代码块中的依赖关系,这样我们仍然可以对代码的其他部分使用 -O3 标志

锁定方法:

void lock(int me)
{
    int other;
    other = 1-me;
    flag[me] = 1; //Line a
    victim = me;  //Line b
    while(flag[other]==1 && victim == me)
    {
    }
}

如果交换行 a 和行 b 的执行顺序,则违反 MUTEX 的示例:

T0 0 sets victim=0
T1 1 sets victim=1
T2 1 sets flag[1]=1
T3 1 checks flag[0]. flag[0] not yet set.
T4 1 enters CS
T5 0 sets flag[0]=1 and checks flag[1]. It is set but victim=1.
T6 0 also enters cs

完整代码:

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<time.h>
#include<stdint.h>
int flag[2];
int victim;
int sharedCounter=0;

void lock(int me)
{
    int other;
    other = 1-me;
    flag[me] = 1;
    victim = me;
    while(flag[other]==1 && victim == me)
    {
    }
}

void unlock(int me)
{
    flag[me]=0;
}

void *peterson(void *ptr)
{
    int tId,i;
    tId = (int ) (intptr_t) ptr;
    for(i=0;i<200;i++)
    {
        lock(tId);
        sharedCounter++;
        printf("%d\t",sharedCounter);
        sleep(1/10);
        unlock(tId);
    }
}

main()
{
    int i;
    for(i=0;i<2;i++)
    {
        flag[i]= 0;
    }
    pthread_t t[2];
    for(i=0;i<2;i++)
    {
        pthread_create(&t[i],NULL,peterson,(void *) (intptr_t) i);
    }

    for(i=0;i<2;i++)
    {
        pthread_join(t[i],NULL);
    }
    printf("shared Counter:%d\n",sharedCounter);
    exit(0);
}

【问题讨论】:

标签: c multithreading algorithm compiler-construction parallel-processing


【解决方案1】:

将变量声明为“易失性”将仅防止对这些变量的读取或写入重新排序。

【讨论】:

  • 这很简单,甚至可以使用 O3 标志。但我认为 volatile 与阻止编译器优化单个变量的指令有关。但是这里我们有一个间接的依赖。可能是我对 volatile 关键字的理解是错误的。你能详细说明一下吗?
  • @arunmoezhi:volatile 合格对象的写入和读取被认为是程序“外部可见”效果的一部分。因此,如果您的程序在读取 volatile 变量 b 之前写入 volatile 变量 a,则写入和读取必须按此顺序进行。但是请注意,如果您的架构允许这样的事情,这并不能阻止 CPU 重新排序您下方的内存访问...
  • @caf:感谢您的回复。 “因此,如果您的程序在读取 volatile 变量 b 之前写入 volatile 变量 a,则写入和读取必须按此顺序进行”。你是说即使读写发生在不同的 volatile 变量上,它们发生的顺序也会被保留?
  • @arunmoezhi:是的,因为这是它们在抽象机器上执行的顺序,所有对 volatile 限定对象的访问都被认为是程序可观察行为的一部分。
  • harbison 和 Steele p91/92 -“不能跨 seq 点优化 volatile 对象的引用和 mods。” seq 点在publications.gbdirect.co.uk/c_book/chapter8/… 中定义(但我在该链接中找不到他们将其与 volatile 联系起来的地方)。无论如何,如果你问这类问题,《h&s》是一本很棒的书。
猜你喜欢
  • 2013-02-17
  • 2011-02-24
  • 1970-01-01
  • 2017-05-05
  • 2014-12-28
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 2020-05-29
相关资源
最近更新 更多