C线程编程-递增共享变量

C线程编程-递增共享变量,c,multithreading,pthreads,C,Multithreading,Pthreads,嘿,伙计们……所以我试图复习一下我的C线程,我发现一个问题是: 给定一个全局变量int x=0;实现函数void untible(int n),它创建n个线程,在循环中,这些线程将x增加1,每个线程在x达到100时终止 我只是没有处理线程,需要一个坚实的例子来建立我的基础。这必须尽可能多地使用pthread系统调用。您需要一个互斥来保护变量。 每个线程将锁定互斥锁,增加变量并释放互斥锁。 每个不这样做的线程都是恶意线程。您需要一个互斥来保护变量。 每个线程将锁定互斥锁,增加变量并释放互斥锁。 每

嘿,伙计们……所以我试图复习一下我的C线程,我发现一个问题是:

给定一个全局变量int x=0;实现函数void untible(int n),它创建n个线程,在循环中,这些线程将x增加1,每个线程在x达到100时终止


我只是没有处理线程,需要一个坚实的例子来建立我的基础。这必须尽可能多地使用pthread系统调用。

您需要一个互斥来保护变量。 每个线程将锁定互斥锁,增加变量并释放互斥锁。
每个不这样做的线程都是恶意线程。

您需要一个互斥来保护变量。 每个线程将锁定互斥锁,增加变量并释放互斥锁。
每个不这样做的线程都是流氓线程。

您需要的是一个关键部分。在windows下,这将是EnterCriticalSection,但在pthread环境中,等效的是
pthread\u mutex\u lock
。请参阅以获取一些提示。

您需要的是一个关键部分。在windows下,这将是EnterCriticalSection,但在pthread环境中,等效的是
pthread\u mutex\u lock
。请参阅以获取一些指针。

如果X>=100时每个线程都可以退出,则我认为联锁增量就足够了


我永远不会使用关键部分,除非我真的必须这样做,因为这可能导致高水平的争论。然而InterlockedIncrement根本没有争用,至少不会影响整体性能。

如果X>=100时每个线程都可以退出,我认为InterlockedIncrement就足够了


我永远不会使用关键部分,除非我真的必须这样做,因为这可能导致高水平的争论。然而InterlockedCredit根本没有争用,至少不会影响整体性能。

首先,您需要确定您要实现的是什么,以及不同线程的指令可以以何种方式交错以防止这种情况发生

C
++x
中的递增运算符通常实现为将i的值从内存读入寄存器;递增寄存器;将值写入内存:

r1 ← xglobal r1 ← r1 + 1 xglobal ← r1 在pthreads之外,您可能希望使用平台的比较和交换操作(
\uuu sync\u val\u compare\u and_swap
in),该操作将一个地址、一个旧值和一个新值进行比较,如果地址等于旧值,则自动将该地址处的内存设置为新值。这使您可以将逻辑编写为:

for ( int v = 0; v < 100; ) {
    int x_prev = __sync_val_compare_and_swap ( &x, v, v + 1 );

    // if the CAS succeeds, the value of x has been set to is x_prev + 1
    // otherwise, try again from current last value
    if ( x_prev == v ) 
        v = x_prev + 1;
    else
        v = x_prev;
}
for(int v=0;v<100;){
int x_prev=u sync_val_compare_和_swap(&x,v,v+1);
//如果CAS成功,则x的值已设置为x_prev+1
//否则,请从当前的最后一个值重试
如果(x_prev==v)
v=x_上一个+1;
其他的
v=x_上一个;
}
所以如果

initial xglobal = 98 initial v1 = 0 initial v2 = 0 cmp v1 100 x_prev1 ← CASV ( xglobal, v1, v1 + 1 ) = 98 ( set fails with x == 98 ) cmp v2 100 x_prev2 ← CASV ( xglobal, v1, v1 + 1 ) = 98 ( set fails with x == 98 ) v1 ← x_prev1 = 98 // x_prev != v v2 ← x_prev2 = 98 cmp v2 100 x_prev2 ← CASV ( xglobal, v1, v1 + 1 ) = 98 ( set succeeds with x == 99 ) v2 ← x_prev2 + 1 = 99 // as x_prev == v cmp v1 100 x_prev1 ← CASV ( xglobal, v1, v1 + 1 ) = 99 ( set fails with x == 99 ) v1 ← x_prev1 = 99 // as x_prev != v cmp v1 100 x_prev1 ← CASV ( xglobal, v1, v1 + 1 ) = 99 ( set succeeds with x == 100) v1 ← x_prev1 + 1 = 100 // as x_prev == v cmp v2 100 x_prev2 ← CASV ( xglobal, v1, v1 + 1 ) = 100 ( set fails with x == 100 ) v2 ← x_prev2 = 100 // as x_prev != v cmp v1 100 cmp v2 100 stop stop 初始xglobal=98 初始v1=0 初始v2=0 cmp v1 100 x_prev1← CASV(xglobal,v1,v1+1)=98(设置失败,x==98) cmp v2 100 x_prev2← CASV(xglobal,v1,v1+1)=98(设置失败,x==98) v1← x_prev1=98//x_prev!=v v2← x_prev2=98 cmp v2 100 x_prev2← CASV(xglobal,v1,v1+1)=98(设置成功,x==99) v2← x_prev2+1=99//as x_prev==v cmp v1 100 x_prev1← CASV(xglobal,v1,v1+1)=99(设置失败,x==99) v1← x_prev1=99//as x_prev!=v cmp v1 100 x_prev1← CASV(xglobal,v1,v1+1)=99(设置成功,x==100) v1← x_prev1+1=100//as x_prev==v cmp v2 100 x_prev2← CASV(xglobal,v1,v1+1)=100(设置失败,x==100) v2← x_prev2=100//as x_prev!=v cmp v1 100 cmp v2 100 停止 停止
在每个循环中,xglobal将原子地设置为r1+1的值,当且仅当其先前的值为r1时;否则,r1将设置为CASV运行期间测试的xglobal值。这减少了大多数实现中持有的时间锁的数量(尽管它仍然需要在CAS操作期间锁定内存总线,但只有那些操作将被串行化。由于在多核上执行CAS的成本很高,对于这样一个简单的情况,可能不会有太大的好处。)

首先,您需要确定您要实现的目标,以及不同线程的指令可以以何种方式交错以防止这种情况发生

C
++x
中的递增运算符通常实现为将i的值从内存读入寄存器;递增寄存器;将值写入内存:

r1 ← xglobal r1 ← r1 + 1 xglobal ← r1 在pthreads之外,您可能希望使用平台的比较和交换操作(
\uuu sync\u val\u compare\u and_swap
in),该操作将一个地址、一个旧值和一个新值进行比较,如果地址等于旧值,则自动将该地址处的内存设置为新值。这使您可以将逻辑编写为:

for ( int v = 0; v < 100; ) {
    int x_prev = __sync_val_compare_and_swap ( &x, v, v + 1 );

    // if the CAS succeeds, the value of x has been set to is x_prev + 1
    // otherwise, try again from current last value
    if ( x_prev == v ) 
        v = x_prev + 1;
    else
        v = x_prev;
}
for(int v=0;v<100;){
int x_prev=u sync_val_compare_和_swap(&x,v,v+1);
//如果CAS成功,则x的值已设置为x_prev+1
//否则,请从当前的最后一个值重试
如果(x_prev==v)
v=x_上一个+1;
其他的
v=x_上一个;
}
所以如果

initial xglobal = 98 initial v1 = 0 initial v2 = 0 cmp v1 100 x_prev1 ← CASV ( xglobal, v1, v1 + 1 ) = 98 ( set fails with x == 98 ) cmp v2 100 x_prev2 ← CASV ( xglobal, v1, v1 + 1 ) = 98 ( set fails with x == 98 ) v1 ← x_prev1 = 98 // x_prev != v v2 ← x_prev2 = 98 cmp v2 100 x_prev2 ← CASV ( xglobal, v1, v1 + 1 ) = 98 ( set succeeds with x == 99 ) v2 ← x_prev2 + 1 = 99 // as x_prev == v cmp v1 100 x_prev1 ← CASV ( xglobal, v1, v1 + 1 ) = 99 ( set fails with x == 99 ) v1 ← x_prev1 = 99 // as x_prev != v cmp v1 100 x_prev1 ← CASV ( xglobal, v1, v1 + 1 ) = 99 ( set succeeds with x == 100) v1 ← x_prev1 + 1 = 100 // as x_prev == v cmp v2 100 x_prev2 ← CASV ( xglobal, v1, v1 + 1 ) = 100 ( set fails with x == 100 ) v2 ← x_prev2 = 100 // as x_prev != v cmp v1 100 cmp v2 100 stop stop 初始xglobal=98 初始v1=0 初始v2=0 cmp v1 100 x_prev1← CASV(xglobal,v1,v1+1)=98(设置失败,x==98) cmp v2 100 x_prev2← CASV(xglobal,v1,v1+1)=98(设置失败,x==98) v1← x_prev1=98//x_prev!=v v2← x_prev2=98 cmp v2 100 x_prev2← CASV(xglobal,v1,v1+1)=