Indexing pthreads with numbers 0 through n -1.

huangapple go评论65阅读模式
英文:

C: Indexing pthreads with numbers 0 through n -1

问题

I've translated the code-related content as requested:

我有一组 n 个需要从 0 到 n - 1 编号的线程。

This does not work right.

这不起作用。

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

#define MY_THREAD_COUNT 6

void *runner(void *param) {
	int id = *(int*)param;
	printf("Thread %d\n", id);
}

int main() {
	pthread_t thread_arr[MY_THREAD_COUNT];
	for (int i = 0; i < MY_THREAD_COUNT; i++)
		pthread_create(&thread_arr[i], NULL, runner, &i);
	for (int i = 0; i < MY_THREAD_COUNT; i++)
		pthread_join(thread_arr[i], NULL);
}

它的输出如下所示:

Thread 2
Thread 2
Thread 3
Thread 4
Thread 5
Thread 6

为每个线程的 ID 号码创建一个指针确实可以正常工作:

	for (int i = 0; i < MY_THREAD_COUNT; i++) {
		int *tmp = malloc(sizeof(int));
		*tmp = i;
		pthread_create(&thread_arr[i], NULL, runner, tmp);
	}

它的输出如下所示:

Thread 0
Thread 1
Thread 2
Thread 4
Thread 5
Thread 3

但由于涉及到动态内存分配,可能会导致内存泄漏等问题,这并不是最理想的解决方案。

是否有一种方法可以从 runner() 内部调用的函数中获取线程的 ID 号码?类似于 pthread_self(),但可以提供序号,从 0 到 n - 1?

或者,更一般地说,有没有更干净的方法来实现这个目标?如果有多种方法可行,你认为哪种最好?

英文:

I've got a set of n threads that need to be numbered 0 to n - 1.

This does not work right.

#include &lt;pthread.h&gt;
#include &lt;stdio.h&gt;

#define MY_THREAD_COUNT 6

void *runner(void *param) {
	int id = *(int*)param;
	printf(&quot;Thread %d\n&quot;, id);
}

int main() {
	pthread_t thread_arr[MY_THREAD_COUNT];
	for (int i = 0; i &lt; MY_THREAD_COUNT; i++)
		pthread_create(&amp;thread_arr[i], NULL, runner, &amp;i);
	for (int i = 0; i &lt; MY_THREAD_COUNT; i++)
		pthread_join(thread_arr[i], NULL);
}

It results in output such as:

> Thread 2<br>Thread 2<br>Thread 3<br>Thread 4<br>Thread 5<br>Thread 6

Creating a pointer for each thread's ID number does work right:

	for (int i = 0; i &lt; MY_THREAD_COUNT; i++) {
		int *tmp = malloc(sizeof(int));
		*tmp = i;
		pthread_create(&amp;thread_arr[i], NULL, runner, tmp);
	}

It results in output such as:

> Thread 0<br>Thread 1<br>Thread 2<br>Thread 4<br>Thread 5<br>Thread 3

However, since it entails mallocing, leaking, yada yada, that's not my ideal solution.

Is there any way to get the id number from a function called inside of runner()? Something like pthread_self() but that would give serial numbers, 0 through n - 1?

Or — to open the question up more generally — what's the overall cleanest way to do this? If any approach is on the table, what do you think is best?

答案1

得分: 2

以下是已翻译的内容:

"你看到的结果是因为在创建的线程与 'main' 线程的运行时间关系上没有保证。你将 'i' 的地址传递给 'runner'。每次都是相同的地址,所以无论 'i' 中的值是什么,'runner' 在运行时都会看到相同的值。更糟糕的是,在线程运行之前 'for' 循环可能会终止(这解释了你得到的 6)... 你只是在那个 6 时刻侥幸地访问了超出作用域的内存。"

可能的解决方案:

#define MY_THREAD_COUNT 6

void *runner(void *param) {
    int id = *(int*)param;
    printf("线程 %d\n", id);
}

int main() {
    pthread_t thread_arr[MY_THREAD_COUNT];
    int threadArgs[MY_THREAD_COUNT];

    for (int i = 0; i < MY_THREAD_COUNT; i++)
    {
        threadArgs[i] = i;
        pthread_create(&thread_arr[i], NULL, runner, &(threadArgs[i]));
    }
    for (int i = 0; i < MY_THREAD_COUNT; i++)
        pthread_join(thread_arr[i], NULL);
}

这将在运行时保持参数的作用域。

英文:

The results you see are because you have no guarantees when the created threads will run in relation to the main thread. You pass the address of i to runner. That's the same address each time, so whatever value is in i is what runner will see when it runs. Even worse, the for loop could terminate before the thread runs (this explains your 6) .. you're just getting lucky with that 6, runner is accessing memory out of scope when that happens.

One possible solution:

#define MY_THREAD_COUNT 6

void *runner(void *param) {
    int id = *(int*)param;
    printf(&quot;Thread %d\n&quot;, id);
}

int main() {
    pthread_t thread_arr[MY_THREAD_COUNT];
    int threadArgs[MY_THREAD_COUNT];

    for (int i = 0; i &lt; MY_THREAD_COUNT; i++)
    {
        threadArgs[i] = i;
        pthread_create(&amp;thread_arr[i], NULL, runner, &amp;(threadArgs[i]));
    }
    for (int i = 0; i &lt; MY_THREAD_COUNT; i++)
        pthread_join(thread_arr[i], NULL);
}

This will keep the arguments in scope for duration of run time.

答案2

得分: 2

以下是您要翻译的代码部分:

#define MY_THREAD_COUNT 6

void *runner(void *param) {
    int id = (int) param;
    printf("Thread %d\n", id);
    return NULL;
}

int main() {
    pthread_t thread_arr[MY_THREAD_COUNT];
    for (int i = 0; i < MY_THREAD_COUNT; i++)
        pthread_create(&thread_arr[i], NULL, runner, (void *) i);
    for (int i = 0; i < MY_THREAD_COUNT; i++)
        pthread_join(thread_arr[i], NULL);
}
英文:

You could do:

#define MY_THREAD_COUNT 6

void *runner(void *param) {
    int id = (int) param;
    printf(&quot;Thread %d\n&quot;, id);
    return NULL;
}

int main() {
    pthread_t thread_arr[MY_THREAD_COUNT];
    for (int i = 0; i &lt; MY_THREAD_COUNT; i++)
        pthread_create(&amp;thread_arr[i], NULL, runner, (void *) i);
    for (int i = 0; i &lt; MY_THREAD_COUNT; i++)
        pthread_join(thread_arr[i], NULL);
}

And then you have no lifetime issues with the parameter passed to the child thread.

huangapple
  • 本文由 发表于 2023年4月11日 05:00:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980690.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定