线程可以写入相同结构数组的不同元素而不锁定吗? [英] Can threads write to different elements of same array of structures without locking?

查看:90
本文介绍了线程可以写入相同结构数组的不同元素而不锁定吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在非线程模式下正常工作的GCC C应用程序中使用线程(第一次!)。当我运行它时,一些线程给出的结果全部为零而不是所需的答案(我知道用于检查目的),但是每次运行它时给出零的线程都不相同。给出非零答案的答案是正确的,所以代码似乎运行正常。我想知道是否有人可以指出我可能有什么东西不是线程安全的。

I'm trying to use threads (for the first time!) in a GCC C application which works fine in non-threaded mode. When I run it some threads give results which are all zero instead of the required answers (which I know for checking purposes), but the threads giving zeroes are not the same each time I run it. The ones which give non-zero answers are correct, so the code appears to run ok as such. I wonder if anyone can point out areas where I might have something which is not thread-safe.

我自己的想法可能是由于我如何收集结果或者可能内存分配 - 我使用malloc和免费,但在StackOverflow其他地方我看到,GCC malloc被认为是线程安全的,如果链接-lpthread(我正在做)。没有使用全局/静态变量 - 一切都作为函数参数传递。

My own thoughts are it may be due to how I collect results or maybe memory allocation - I use malloc and free but elsewhere in StackOverflow I see that GCC malloc is considered thread-safe if linked with -lpthread (which I am doing). Nothing uses global/static variables - everything is passed as function arguments.

为了将结果传递回main,我的线程例程使用一个结构数组。每个线程写入此数组的一个独特元素,因此它们不会尝试写入相同的内存。也许我在编写结果时需要使用某种形式的锁定,即使它们不会与结构数组中的元素相同吗?

In order to pass results back to main, my threaded routine uses an array of structures. Each thread writes to a distinct element of this array, so they are not trying to write to the same memory. Maybe I need to use some form of locking when writing results even though they don't go to the same element of the structure array?

我遵循线程代码的配方这里:
https://computing.llnl.gov/tutorials/pthreads/#Abstract

I followed the recipe for threaded code here: https://computing.llnl.gov/tutorials/pthreads/#Abstract

我附上(简体)代码提取以防万一这会给出任何线索(我可能会忽略/修改某些错误,但我不会要求任何人发现错误,只是一般的方法)。

I attach (simplified) code extracts in case this gives any clues (I may have omitted/modified something incorrectly but I am not asking for anyone to spot bugs, just the general methodology).

typedef struct p_struct { /* used for communicating results back to main */
    int given[CELLS];
    int type;
    int status;
    /*... etc */
} puzstru;

typedef struct params_struct { /* used for calling generate function using threads */
    long seed;
    char *text;
    puzzle *puzzp;
    bool unique;
    int required;
} paramstru;
/* ========================================================================================== */
void *myfunc(void *spv) /* calling routine for use by threads */
{
    paramstru *sp=(paramstru *)spv;
    generate(sp->seed, sp->text, sp->puzzp, sp->unique, sp->required);
    pthread_exit((void*) spv);
}
/* ========================================================================================== */
int generate(long seed, char *text, puzstru *puzzp, bool unique, int required)
{
/* working code , also uses malloc and free,
    puts results in the element of a structure array pointed to by "puzzp", 
    which is different for each thread
    (see calling routine below :        params->puzzp=puz+thr; )
    extract as follows: */
            puzzp->given[ix]=calcgiven[ix];
            puzzp->type=1; 
            puzzp->status=1;
            /* ... etc */
}
/* ========================================================================================== */


int main(int argc, char* argv[])
{
    pthread_t thread[NUM_THREADS];
    pthread_attr_t threadattr;
    int thr,threadretcode;
    void *threadstatus;
    paramstru params[1];

    /* ....... ETC */

/* set up params structure for function calling parameters */
    params->text=mytext;
    params->unique=TRUE;
    params->required=1;

    /* Initialize and set thread detached attribute */
    pthread_attr_init(&threadattr);
    pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_JOINABLE);

    for(thr=0; thr<NUM_THREADS; thr++)
    {
        printf("Main: creating thread %d\n", thr);
        params->seed=ran_arr_next(startingseeds); 
        params->puzzp=puz+thr;
        threadretcode = pthread_create(&thread[thr], &threadattr, myfunc, (void *)params); 
        if (threadretcode)
        {
            printf("ERROR; return code from pthread_create() is %d\n", threadretcode);
            exit(-1);
        }
    }

    /* Free thread attribute and wait for the other threads */
    pthread_attr_destroy(&threadattr);
    for(thr=0; thr<NUM_THREADS; thr++)
    {
        threadretcode = pthread_join(thread[thr], &threadstatus);
        if (threadretcode)
        {
            printf("ERROR; return code from pthread_join() is %d\n", threadretcode);
            exit(-1);
        }
        printf("Main: completed join with thread %d having a status of %ld\n",thr,(long)threadstatus);
    }

/* non-threaded code, print results etc ............. */

    free(startingseeds);
    free(puz);
    printf("Main: program completed. Exiting.\n");
    pthread_exit(NULL);
}

为了读者的利益 - 所有答案都是正确的,回答标题中的问题是YES,线程可以安全地写入相同结构数组的不同元素,我的问题在调用例程中 - 以下是修改后的代码片段(现在可以正常工作):

For the benefit of others reading this - all the answers were correct, and the answer to the question in the heading is YES, threads can write safely to different elements of the same array of structures, my problem was in the calling routine - the following is the amended code snippet (now works fine):

    paramstru params[NUM_THREADS];

    for(thr=0; thr<NUM_THREADS; thr++)
    {
        printf("Main: creating thread %d\n", thr);
    /* set up params structure for function calling parameters */
        params[thr].text=mytext;
        params[thr].unique=TRUE;
        params[thr].required=1;
        params[thr].seed=ran_arr_next(startingseeds); 
        params[thr].puzzp=puz+thr;
        threadretcode = pthread_create(&thread[thr], &threadattr, myfunc, (void *)&params[thr]); 
        if (threadretcode)
        {
            printf("ERROR; return code from pthread_create() is %d\n", threadretcode);
            exit(-1);
        }
    }


推荐答案

paramstru params[1];

代码将相同的结构传递给所有线程。只有线程初始化循环覆盖了线程应该工作的数据:

The code is passing the same structure to all threads. Just the thread initialization loop is overwriting the data that a thread should work on:

for(thr=0; thr<NUM_THREADS; thr++)
    {
        printf("Main: creating thread %d\n", thr);
        params->seed=ran_arr_next(startingseeds); /* OVERWRITE  */
        params->puzzp=puz+thr; /* OVERWRITE  */

非线程代码工作的原因是每次调用 myfunc() params 结构发生变化之前终止。

The reason the non-threaded code works is because each call to myfunc() terminates before the params structure is changed.

这篇关于线程可以写入相同结构数组的不同元素而不锁定吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆