Cygwin和Linux不同环境多线程加锁的差异

深夜本来都打算弄完睡觉,结果被一个莫名其妙的锁搞得莫名其妙,为了让同步问题明显地表现出来,主线程和子线程都加了一个sleep 1秒,使得都来不及减减操作,if判断就都为真,导致结果变成了-1,但这不是想要的结果

于是想通过互斥量加锁,让一个if以及减减线执行完,然后解锁再执行另一个,可居然还是返回-1,更奇怪的是,去掉两个线程里的sleep,锁就起效果了,难道是这中间的具体实现流程问题没完全弄清楚?

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

int i = 1;
pthread_mutex_t mutex;

void *thread_function(){
    pthread_mutex_lock(&mutex);
    if (i > 0){
        sleep(1);
        --i;
    }
    pthread_mutex_unlock(&mutex);
    pthread_exit("See you, lihui");
}

int main(){
    pthread_t child;
    if (pthread_create(&child, NULL, thread_function, NULL)){
        printf("Create new thread failed!\n");
        exit(1);
    }
    pthread_mutex_lock(&mutex);
    if (i > 0){
        sleep(1);
        --i;
    }
    pthread_mutex_unlock(&mutex);
    pthread_join(child, NULL);
    printf("i = %d\n", i);
    return 0;
}

执行,神奇的结果:

lihui@2015 ~
$ ./a.exe
i = -1

这就很奇怪了,这锁应该加得没问题呀,只好gdb了一把,但是神奇的一幕出现了:

Reading symbols from ./a.exe...done.
(gdb) b 12
Breakpoint 1 at 0x1004010f1: file he.c, line 12.
(gdb) b 27
Breakpoint 2 at 0x100401184: file he.c, line 27.
(gdb) r
Starting program: /home/lihui/a.exe
[New Thread 6772.0x1b9c]
[New Thread 6772.0xf3c]
[New Thread 6772.0x1da4]

Breakpoint 2, main () at he.c:27
27              sleep(1);
(gdb) c
Continuing.
[Switching to Thread 6772.0x1da4]

Breakpoint 1, thread_function () at he.c:12
12              sleep(1);
(gdb) c
Continuing.
[Thread 6772.0x1da4 exited with code 0]
i = -1

主线程和子线程的if判断居然都为真,也就是这锁完全没起作用?这就奇怪了,这么简单的程序,感觉没明显错误呀,抱着试一试的态度,把两个sleep给去掉,不试不知道,一试吓一跳:

lihui@2015 ~
$ ./a.exe
i = 0

但其实这样做是没道理的,因为没有了sleep,不加锁执行结果也会是0,就因为这样我猜加了两个sleep凸显一下问题,但事实上加了sleep的确结果就变了,已经开始怀疑在锁里加sleep会不会有不明确的问题,还搜索了半天,一无所获

准备收工睡觉的时候,不死心,心想会不会是cygwin的问题,直接copy sourcecode到服务器linux系统执行了一把,神了,加sleep结果也是0,顿时心中突然冒出来多少只那啥,上次一个程序也是,还好这次没浪费太多时间

[lihui@localhost ~]# gcc -g hello.c -lpthread
[lihui@localhost ~]# ./a.out 
i = 0
...
Reading symbols from /root/a.out...done.
(gdb) b 12
Breakpoint 1 at 0x4007ac: file hello.c, line 12.
(gdb) b 27
Breakpoint 2 at 0x400828: file hello.c, line 27.
(gdb) r
Starting program: /root/a.out 
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff7ff2700 (LWP 9063)]

Breakpoint 2, main () at hello.c:27
27	        sleep(1);
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.x86_64
(gdb) c
Continuing.
i = 0
[Thread 0x7ffff7ff2700 (LWP 9063) exited]

Program exited normally.
Missing separate debuginfos, use: debuginfo-install libgcc-4.4.7-4.el6.x86_64
(gdb) 

果然,只跳进去了一个sleep,锁生效了,难道cygwin和linux有关thread加锁也有这么大差异??

发表评论