线程程序中的C - malloc



下面的代码摘录一般会导致任何问题吗?

void * fct(void * p)
{
  int i = 0;
  int * input = (int *) p;
  int * arr = malloc((*input)*sizeof(int));
  /* put something in arr */
  return (void *) arr
}
int main()
{
  /* prologue */
  for (i = 0; i < MAX_THREADS; i++)
  {
    rc = pthread_create(&threads[i], NULL, fct, (void *) &input[i]);
  }
  /* epilogue */
}

我实际上不理解并没有找到答案是:线程例程(i, input, arr)内的变量共享吗?我理解pthreads的方式是fct的不同副本被称为MAX_THREADS次,每个副本都有自己的一组变量。

全局变量在线程之间共享。作为参数传递的输入的引用也是如此。

另一方面,您引用的变量是局部变量,它们在堆栈上分配并且彼此不同。这与线程无关,而是与堆栈指针的当前值有关。malloc的结果也会有所不同,因为malloc会被调用多次。

所有这些都与线程的关系非常松散,并且在同一个线程中对函数的几个调用将表现出相同的内存(而不是时间)。在局部变量方面会有细微的区别,因为堆栈不是在线程之间共享的,仅此而已。

对于您的问题"是否…代码摘录一般会导致任何问题"的简洁回答是"否"。正如在各种评论和回答中所指出的:

函数中的局部自动变量本质上是线程安全的;无论在线程上下文中、递归上下文中还是对函数的简单调用中,每次调用函数都会重新分配它们。全局变量通常是共享的——除非创建为线程本地存储(TLS)或线程特定存储(TSS——C11中使用的术语)。代码[在问题]应该是好的,除了内存泄漏时,线程返回-但线程清理代码没有显示,所以这可能是不公平的。您需要通过pthread_join()捕获返回值并释放它以避免泄漏。

将代码摘录充实为工作代码,使用互斥锁来显示并确保一次一个线程正在打印其数据,您可以编写如下代码:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static void *fct(void *p)
{
    int number = *(int *)p;
    int *arr = malloc(number * sizeof(int));  // Error check missing!
    for (int i = 0; i < number; i++)
        arr[i] =  number + (7 * i + 5) % 11;
    pthread_mutex_lock(&mtx);   // Error check missing!
    printf("Integers %2d (%p):", number, (void *)arr);
    for (int i = 0; i < number; i++)
        printf(" %3d", arr[i]);
    putchar('n');
    pthread_mutex_unlock(&mtx); // Error check missing!
    return (void *)arr;
}
enum { MAX_THREADS = 10 };
int main(void)
{
    pthread_t threads[MAX_THREADS];
    int input[MAX_THREADS];
    int *result[MAX_THREADS];
    /* Initialization */
    for (int i = 0; i < MAX_THREADS; i++)
        input[i] = (3 * i + 2) % 13 + 1;
    /* Thread creation */
    for (int i = 0; i < MAX_THREADS; i++)
    {
        pthread_mutex_lock(&mtx);   // Error check missing!
        printf("Launch %d: %2dn", i, input[i]);
        pthread_mutex_unlock(&mtx); // Error check missing!
        int rc = pthread_create(&threads[i], NULL, fct, (void *)&input[i]);
        if (rc != 0)
        {
            fprintf(stderr, "Oops creating thread %dn", i);
            exit(EXIT_FAILURE);
        }
    }
    /* Thread harvesting */
    for (int i = MAX_THREADS; i-- > 0; )
    {
        void *vp;
        int rc = pthread_join(threads[i], &vp);
        if (rc != 0)
        {
            fprintf(stderr, "Oops joining thread %dn", i);
            exit(EXIT_FAILURE);
        }
        printf("Thread %d: %2d (%p)n", i, input[i], vp);
        result[i] = vp;
    }
    /* Finalization */
    for (int i = 0; i < MAX_THREADS; i++)
    {
        printf("Master - %d:", i);
        for (int j = 0; j < input[i]; j++)
            printf(" %3d", result[i][j]);
        putchar('n');
        free(result[i]);
    }
    pthread_mutex_destroy(&mtx);
    return 0;
}

运行示例
Launch 0:  3
Launch 1:  6
Launch 2:  9
Launch 3: 12
Integers  6 (0x7faf9ae01890):  11   7  14  10   6  13
Integers  3 (0x7faf9af00000):   8   4  11
Integers  9 (0x7faf9b800000):  14  10  17  13   9  16  12  19  15
Launch 4:  2
Integers 12 (0x7faf9b800030):  17  13  20  16  12  19  15  22  18  14  21  17
Launch 5:  5
Integers  2 (0x7faf9af00010):   7   3
Integers  5 (0x7faf9b800060):  10   6  13   9   5
Launch 6:  8
Launch 7: 11
Integers  8 (0x7faf9ae018b0):  13   9  16  12   8  15  11  18
Launch 8:  1
Integers 11 (0x7faf9b800080):  16  12  19  15  11  18  14  21  17  13  20
Launch 9:  4
Integers  1 (0x7faf9af00020):   6
Integers  4 (0x7faf9b8000b0):   9   5  12   8
Thread 9:  4 (0x7faf9b8000b0)
Thread 8:  1 (0x7faf9af00020)
Thread 7: 11 (0x7faf9b800080)
Thread 6:  8 (0x7faf9ae018b0)
Thread 5:  5 (0x7faf9b800060)
Thread 4:  2 (0x7faf9af00010)
Thread 3: 12 (0x7faf9b800030)
Thread 2:  9 (0x7faf9b800000)
Thread 1:  6 (0x7faf9ae01890)
Thread 0:  3 (0x7faf9af00000)
Master - 0:   8   4  11
Master - 1:  11   7  14  10   6  13
Master - 2:  14  10  17  13   9  16  12  19  15
Master - 3:  17  13  20  16  12  19  15  22  18  14  21  17
Master - 4:   7   3
Master - 5:  10   6  13   9   5
Master - 6:  13   9  16  12   8  15  11  18
Master - 7:  16  12  19  15  11  18  14  21  17  13  20
Master - 8:   6
Master - 9:   9   5  12   8

充分披露:

在Mac OS X 10.11.6上测试,GCC 6.1.0和Valgrind 3.12.0.SVN。当在Valgrind下运行时,它会崩溃。当不在Valgrind下运行时不会崩溃。

==3412== Memcheck, a memory error detector
==3412== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3412== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==3412== Command: ./pth37
==3412== 
Launch 0:  3
Launch 1:  6
Launch 2:  9
Launch 3: 12
Launch 4:  2
Integers  3 (0x100aaf5b0):   8   4  11
Launch 5:  5
Integers 12 (0x100aaf600):  17  13  20  16  12  19  15  22  18  14  21  17
Integers  6 (0x100aaf670):  11   7  14  10   6  13
Integers  9 (0x100aaf6d0):  14  10  17  13   9  16  12  19  15
Integers  2 (0x100aaf740):   7   3
Launch 6:  8
Integers  5 (0x100aaf790):  10   6  13   9   5
Launch 7: 11
Integers  8 (0x100aaf7f0):  13   9  16  12   8  15  11  18
Launch 8:  1
Integers 11 (0x100aaf850):  16  12  19  15  11  18  14  21  17  13  20
Launch 9:  4
==3412== 
==3412== Process terminating with default action of signal 11 (SIGSEGV)
==3412==  Access not within mapped region at address 0x700003062C1A
==3412==    at 0x10046F374: _pthread_find_thread (in /usr/lib/system/libsystem_pthread.dylib)
==3412==    by 0x10046F2CF: _pthread_lookup_thread (in /usr/lib/system/libsystem_pthread.dylib)
==3412==    by 0x10047061A: pthread_join (in /usr/lib/system/libsystem_pthread.dylib)
==3412==    by 0x100000C3C: main (pth37.c:52)
==3412==  If you believe this happened as a result of a stack
==3412==  overflow in your program's main thread (unlikely but
==3412==  possible), you can try to increase the size of the
==3412==  main thread stack using the --main-stacksize= flag.
==3412==  The main thread stack size used in this run was 8388608.
--3412:0:schedule VG_(sema_down): read returned -4
==3412== 
==3412== HEAP SUMMARY:
==3412==     in use at exit: 26,557 bytes in 196 blocks
==3412==   total heap usage: 280 allocs, 84 frees, 32,789 bytes allocated
==3412== 
Memcheck: mc_leakcheck.c:1106 (void lc_scan_memory(Addr, SizeT, Bool, Int, Int, Addr, SizeT)): Assertion 'bad_scanned_addr >= VG_ROUNDUP(start, sizeof(Addr))' failed.
host stacktrace:
==3412==    at 0x238050773: ???
==3412==    by 0x238050B9C: ???
==3412==    by 0x238050B7A: ???
==3412==    by 0x238003B86: ???
==3412==    by 0x2380033A6: ???
==3412==    by 0x238002050: ???
==3412==    by 0x238014F0D: ???
==3412==    by 0x23805D562: ???
==3412==    by 0x2380F2772: ???
==3412==    by 0x2380F287A: ???
sched status:
  running_tid=2

出于礼貌,我对此感到困惑。

你正在做的事情正在引起问题。pthread_create返回一个错误代码。从手册页:

如果成功,pthread_create()返回0;当出现错误时,它返回一个错误, *线程的内容未定义。

你不能这样返回指向malloc的指针。你必须有一个全局的指针数组,你的线程可以保存它的malloc结果,或者你必须传递一个指针作为参数。如果你有超过1个参数,你想传递给一个线程,我知道如何做到这一点的唯一方法是使用struct

相关内容

  • 没有找到相关文章

最新更新