多线程中丢失的数据

时间:2018-03-13 01:13:42

标签: linux multithreading thread-safety pthreads

我使用pthread_create创建了许多线程,在每个线程中,我使用线程id作为输入来生成名称字符串thread_<id>,这是有问题的代码:

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

#define THREAD_NUM 40

void *common_function(void *arg);

int main (void)
{
    int             res;
    unsigned int    i;
    pthread_t       t[THREAD_NUM];

    memset(t, 0x0, sizeof(t));

    for(i = 0; i < THREAD_NUM; i++)
    {
        /* pass info */
        res = pthread_create(&(t[i]), NULL, common_function, (void *)&i);
        if(res !=0)
        {
            printf("thread: %d create fail\n", i);
            return -1;
        }
    }

    for(i=0; i<THREAD_NUM; i++)
    {
        pthread_join(t[i], NULL);
    }

    return 0;
}

void *common_function(void *arg)
{
    unsigned int    p;
#ifdef WRITE_FILE
    FILE            *fd;
    char            name[64];
#endif

    p = *(unsigned int *)arg;
#ifdef WRITE_FILE
    memset(name, 0x0, sizeof(name));
    sprintf(name, "thread_%02d", p);
    fd = fopen(name, "w");
    if(fd < 0 )
    {
        printf("create: %s fail\n", name);
        pthread_exit((void *)&p);
    }
#endif

#ifdef WRITE_FILE
    fprintf(fd, "%02d\n", p);
#else
    printf("thread: %02d\n",p);
#endif
    usleep(1);

#ifdef WRITE_FILE
    fclose(fd);
#endif

    pthread_exit((void *)&p);
}

我编译了代码使用(我没有看到任何警告):

gcc -Wall -g -pthread -D_REENTRANT -DWRITE_FILE ./test_thread_problem.c

输出是:

-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_02
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_03
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_04
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_05
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_06
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_07
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_08
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_09
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_11
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_12
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_13
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_14
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_16
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_17
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_18
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_19
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_20
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_21
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_22
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_23
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_24
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_25
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_26
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_28
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_29
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_31
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_32
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_33
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_34
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_35
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_36
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_37
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_38
-rw-rw-r-- 1 haochen haochen    3  3月 13 08:56 thread_39

您可能会发现错过了一些文件,但在致电pthread_createfopen后,它永远不会打印出失败信息。我更改为仅在没有创建文件的情况下打印(没有-DWRITE_FILE选项),也可以看到问题:

./a.out
thread: 03
thread: 07
thread: 03
thread: 04
thread: 04
thread: 05
thread: 06
thread: 15
thread: 19
thread: 19
thread: 19
thread: 19
thread: 19
thread: 19
thread: 20
thread: 20
thread: 20
thread: 20
thread: 20
thread: 20
thread: 21
thread: 22
thread: 23
thread: 27
thread: 29
thread: 29
thread: 31
thread: 37
thread: 38
thread: 38
thread: 38
thread: 38
thread: 38
thread: 38
thread: 38
thread: 39
thread: 04
thread: 05
thread: 18
thread: 18

有什么问题?

1 个答案:

答案 0 :(得分:1)

您为所有线程传递相同的i参数。

res = pthread_create(&(t[i]), NULL, common_function, (void *)&i);
                                                             ^^

这导致竞争条件,因为主线程修改i,而所有其他线程从i读取。我建议你为每个线程使用不同的变量。

unsigned int    tid[THREAD_NUM];
...
for(i = 0; i < THREAD_NUM; i++) {
    /* pass info */
    tid[i] = i;
    res = pthread_create(&(t[i]), NULL, common_function, (void *)&tid[i]);
    ...