socay2 发表于 2014-04-05 22:42

linux 线程在未同步的情况下,输出着实没看懂!

/*使用原子锁实现线程同步*/

#include <alsa/iatomic.h>
#include <pthread.h>
#include <stdio.h>

// 定义一个原子变量
static atomic_t g_atomic;
// 定义共享资源
static volatile int g_i = 0;

/* 定义线程处理函数 */
#define atomic_dec_and_test(g_atomic) 1
void *thr1_handle(void *arg)
{
    while (1) {
      if (atomic_dec_and_test(&g_atomic)) {
            printf("in thread %lu g_i = %d\n", pthread_self(), ++g_i);
      }
      atomic_inc(&g_atomic);
      sleep(1);
    }

    return NULL;   
}

void *thr2_handle(void *arg)
{
    while (1) {
      if (atomic_dec_and_test(&g_atomic)) {
            printf("in thread %lu g_i = %d\n", pthread_self(), --g_i);
      }
      atomic_inc(&g_atomic);
      sleep(1);
    }
    return NULL;   
}


/* 主函数 */
int main()
{
    // 主线程初始化原子变量
    //g_atomic = ATOMIC_INIT(0);
    g_atomic.counter = 1;

    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, thr1_handle, NULL) != 0) {
      fprintf(stderr, "create thread1 failed!\n");
      return 1;
    }
    if (pthread_create(&tid2, NULL, thr2_handle, NULL) != 0) {
      fprintf(stderr, "create thread2 failed!\n");
      return 2;
    }

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    return 0;
}在不使用原子操作来做同步的情况下,程序输出如下:
in thread 3075713856 g_i = 1
in thread 3067321152 g_i = 0
in thread 3067321152 g_i = -1
in thread 3075713856 g_i = 1
in thread 3067321152 g_i = 0
in thread 3075713856 g_i = 1
in thread 3075713856 g_i = 2
in thread 3067321152 g_i = 0
in thread 3075713856 g_i = 3
in thread 3067321152 g_i = 1
in thread 3075713856 g_i = 4
in thread 3067321152 g_i = 2
in thread 3075713856 g_i = 5
in thread 3067321152 g_i = 3
in thread 3075713856 g_i = 6
in thread 3067321152 g_i = 5
in thread 3067321152 g_i = 4
in thread 3075713856 g_i = 6
in thread 3075713856 g_i = 5
in thread 3067321152 g_i = 3
in thread 3075713856 g_i = 6
in thread 3067321152 g_i = 4
in thread 3067321152 g_i = 3
in thread 3075713856 g_i = 5
in thread 3075713856 g_i = 6
in thread 3067321152 g_i = 4
in thread 3067321152 g_i = 5
in thread 3075713856 g_i = 6
in thread 3075713856 g_i = 7
in thread 3067321152 g_i = 5
在输出标红的部分,线程切换时为什么值会出现跳跃增加或减少呢?
按照程序逻辑,在没进入线程一次,只做一次值的加或减呀,怎是怎么个情况? 期待大V指点下

井蛙夏虫 发表于 2014-04-06 00:23

将++g_i(或--g_i)理解为一下三句,就能解释这样的输出产生的原因:
register = memory(g_i);
register = register + 1(或register = register - 1);
memory(g_i) = register;

socay2 发表于 2014-04-06 02:10

井蛙夏虫 发表于 2014-04-06 00:23 static/image/common/back.gif
将++g_i(或--g_i)理解为一下三句,就能解释这样的输出产生的原因:
register = memory(g_i);
register = r ...
谢谢你,井蛙夏虫!
你的意思是说 前++/--这种操作被打断导致上面的情况。可是我不是太明白,请原谅我的愚昧
printf ++g_i 的时候,打印的就是 g_i 所在内存的值,即:
in thread 3075713856 g_i = 1   此时 g_i 内存单元的值为 1
in thread 3075713856 g_i = 2   此时 g_i 内存单元的值为 2
in thread 3067321152 g_i = 0   此时线程切换,--g_i 是取g_i内存的值然后减1,然后将值压入printf的函数栈,怎么就变成0了呢?
in thread 3075713856 g_i = 3
in thread 3067321152 g_i = 1
in thread 3075713856 g_i = 4
期待你的更详细的讲解。

timespace 发表于 2014-04-06 18:44

2楼都写明白了吧,++和--都不是atomic操作,为什么还是将--g_i理解为一次执行完毕呢?请至少分为三个独立指令,而且执行每个指令后,都可能切换到另外一个线程。
BTW:这算典型的undefined行为,知道不可取就可以了,还深究什么?就好比“malloc一次,free两次,为什么有时候core,有时不core?”,点到即止。

socay2 发表于 2014-04-06 21:14

timespace 发表于 2014-04-06 18:44 static/image/common/back.gif
2楼都写明白了吧,++和--都不是atomic操作,为什么还是将--g_i理解为一次执行完毕呢?请至少分为三个独立指 ...

谢谢指点。
我已知道 ++/-- 不是原子操作,可是我还是不是很明白,能给我做一个深度剖析吗?
in thread 3075713856 g_i = 1         正常
in thread 3067321152 g_i = 0         正常
in thread 3067321152 g_i = -1         正常
in thread 3075713856 g_i = 1         不正常
in thread 3067321152 g_i = 0         正常
in thread 3075713856 g_i = 1         正常
in thread 3075713856 g_i = 2         正常
in thread 3067321152 g_i = 0         不正常
in thread 3075713856 g_i = 3         不正常
in thread 3067321152 g_i = 1         不正常
in thread 3075713856 g_i = 4         不正常
in thread 3067321152 g_i = 2         不正常
in thread 3075713856 g_i = 5         不正常
in thread 3067321152 g_i = 3         不正常
in thread 3075713856 g_i = 6         不正常
从地一个不正常分析。
在本次打印之前,线程3067321152已将g_i的值修改为-1,然后在本次打印的结果却是 1 ,说明本次取到的 g_i 的值为0.   从上面的线程执行情况看,只有在第二行的时候值为0,即在线程 3067321152 中。 难道是in thread 3067321152 g_i = -1还没有及时写入内存,此时发生线程切换,切换到 in thread 3075713856 g_i = 1,这个时候取到的就是 0
不知道这样理解对不对。

timespace 发表于 2014-04-06 22:15

线程栈相互独立,有各自的寄存器。

/* 从输出1~4行推断,第3行输出之前g_i = 0 ,下面分解第3行和第4行可能执行顺序 */
t1(++)   r1 = g_i   /* r1是t1的寄存器, g_i = 0那么 r1= 0 */
t2(--)   r2 = g_i   /* r2 = 0 */
t1(++)   r1 += 1   /* r1 = 1 */
t2(--)   r2 -= 1      /* r2 = -1 */
t2(--)   g_i = r2   /* g_i = -1 */
t1(++)   g_i = r1   /* g_i = 1 */
/* 不同步,执行是随机的,出现其它结果也不奇怪 */

socay2 发表于 2014-04-07 00:44

timespace 发表于 2014-04-06 22:15 static/image/common/back.gif
线程栈相互独立,有各自的寄存器。

/* 从输出1~4行推断,第3行输出之前g_i = 0 ,下面分解第3行和第4行可 ...

恩,看来我在上一楼的理解是对的。
谢谢你这直观的分析!
页: [1]
查看完整版本: linux 线程在未同步的情况下,输出着实没看懂!