2

我是 C 中多线程的新手,我有这个问题。我写了以下代码:

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

pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;
pthread_attr_t attr;

void* test(void *a)
{
    int i=*((int *)a);
    printf("The thread %d has started.\n",i);
    pthread_mutex_lock(&m);
    sleep(1);
    printf("The thread %d has finished.\n",i);
    pthread_mutex_unlock(&m);
    pthread_exit(NULL);

}

int main()
{
    int i=0;
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
    pthread_t thread[5];

    for (i=0;i<5;i++)
        pthread_create(&thread[i],&attr,test,&i);

    for (i=0;i<5;i++)
        pthread_join(thread[i],NULL);
    return 0;
}

为什么我会得到如下值:

The thread 0 has started.
The thread 0 has started.
The thread 5 has started.
The thread 5 has started.
The thread 0 has started.
The thread 0 has finished.
The thread 0 has finished.
The thread 5 has finished.
The thread 5 has finished.
The thread 0 has finished.

或者

The thread 1 has started.
The thread 2 has started.
The thread 5 has started.
The thread 4 has started.
The thread 0 has started.
The thread 1 has finished.
The thread 2 has finished.
The thread 5 has finished.
The thread 4 has finished.
The thread 0 has finished.

甚至:

The thread 0 has started.
The thread 0 has started.
The thread 0 has started.
The thread 0 has started.
The thread 0 has started.
The thread 0 has finished.
The thread 0 has finished.
The thread 0 has finished.
The thread 0 has finished.
The thread 0 has finished.

等,当我期望得到:

The thread 0 has started.
The thread 1 has started.
The thread 2 has started.
The thread 3 has started.
The thread 4 has started.
The thread 0 has finished.
The thread 1 has finished.
The thread 2 has finished.
The thread 3 has finished.
The thread 4 has finished.

只有当我放在usleep(10)后面时thread_create,我才能得到一些“正常”的值。

我在 Unix 上的 Code::Blocks 中编译并运行了这段代码。

4

2 回答 2

5

您正在传递for正在更改的变量的地址 ( i),因此您受调度程序的支配。你应该只是传递一个副本。作为一种便宜的,不完全洁净的方式:

pthread_create(&thread[i],&attr,test, (void*)i);

/* ... */

int i = (int)a;
于 2013-01-02T21:46:25.883 回答
2

请注意,您将地址i作为参数传递给线程:

pthread_create(&thread[i],&attr,test,&i);

这意味着您的所有线程都将读取相同的变量i以确定它们是哪个线程。也就是说,所有五个线程都将查看同一个变量来确定它们的线程号。因此,随着循环中的值i递增for,所有线程都会感知到它们的线程号发生变化以使用i. 这就是为什么您有时会看到 5 作为线程编号出现的原因,也解释了您经常跳过数字或看到太多重复项的事实。

要解决此问题,您需要为每个线程提供自己的i. 例如,您可以执行以下操作:

int* myI = malloc(sizeof(int));
*myI = i;
pthread_create(&thread[i], &attr, test, myI);

然后让线程在终止之前释放指针:

void* test(void *a)
{
    int i=*((int *)a);
    printf("The thread %d has started.\n",i);
    pthread_mutex_lock(&m);
    sleep(1);
    printf("The thread %d has finished.\n",i);
    pthread_mutex_unlock(&m);
    pthread_exit(NULL);
    free(a);
}

或者,您可以i转换为 avoid*并将其传入:

pthread_create(&thread[i],&attr,test, (void*)i);

如果您这样做,那么您将让线程将它们的参数直接转换回int,而不是int*

void* test(void *a)
{
    int i = (int)a;
    printf("The thread %d has started.\n",i);
    pthread_mutex_lock(&m);
    sleep(1);
    printf("The thread %d has finished.\n",i);
    pthread_mutex_unlock(&m);
    pthread_exit(NULL);
}

希望这可以帮助!

于 2013-01-02T21:48:10.997 回答