以下代码摘录是否会导致一般问题:
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
次,每个副本都有自己的一组变量。
答案 0 :(得分:2)
全局变量在线程之间共享。对您作为参数传递的输入的引用也是如此。
另一方面,您所引用的变量是本地人,在堆栈上分配并且彼此不同。这与线程无关,而与堆栈指针的当前值无关。 malloc的结果也会有所不同,因为malloc被多次调用。
所有这些与线程的关系非常松散,并且在同一个线程中对函数的多次调用将在内存方面表现相同(不是按时间)。关于局部变量会有一些细微的差别,因为在线程之间不会共享堆栈。
您的代码无法编译。
答案 1 :(得分:1)
对您的问题的简洁回答&#34; ...代码摘录是否导致一般问题&#34;是&#34;不&#34;。正如各种评论和答案所述:
函数中的本地自动变量本质上是线程安全的;它们被重新分配给函数的每次调用,无论是在线程上下文中还是在递归上下文中,或者是对函数的简单调用。通常全局变量是共享的 - 除非创建为线程本地存储(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: %2d\n", 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 %d\n", 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 %d\n", 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
完全披露:
使用GCC 6.1.0和Valgrind 3.12.0.SVN在Mac OS X 10.11.6上测试。并且,当在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
我对此感到困惑,对此我很有礼貌。
答案 2 :(得分:0)
您正在做的事情导致问题。 pthread_create
会返回错误代码。从手册页:
成功时,
pthread_create()
返回0;出错时,会返回错误 数字,*线程的内容未定义。
您无法以这种方式将指针返回malloc
。您必须拥有一个全局指针数组,您的线程可以将其malloc
结果保存在其中,或者您必须将指针作为参数传递。如果你想要传递给一个线程有多个参数,我知道如何做的唯一方法是使用struct
。