1

我不确定下面的程序有什么问题,但它不会打印每种语言一次,而是随机地多一些,少一些,有些不会打印

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



char *messages[] = { 
    "English: Hello World!", 
    "French: Bonjour, le monde!",
    "Spanish: Hola al mundo", 
    "Klingon: Nuq neH!",
    "German: Guten Tag, Welt!", 
    "Russian: Zdravstvytye, mir!",
    "Japan: Sekai e konnichiwa!", 
    "Latin: Orbis, te saluto!"
};
#define NUM_MESSAGES (sizeof( messages ) / sizeof( char* ))


void *PrintHello( void *messageid )
{
    pthread_t taskid;
    int *id_ptr, message_num;

    taskid = pthread_self();
    printf( "This is thread with ID %lu.\n", taskid );

    message_num = *((int *) messageid);
    printf( "%s \n", messages[message_num] );

    pthread_exit( NULL );
}

int main( int argc, char *argv[] ) 
{
    pthread_t threads[NUM_MESSAGES];
    int rc, i;


    for( i = 0; i < NUM_MESSAGES; i++ ) {
        void * argument = (void*) &i;
        rc = pthread_create( &threads[i], NULL, PrintHello, argument );
        if( rc ) {
            printf( "ERROR; return code from pthread_create() is %d\n", rc );
            exit( -1 );
        }
    }




    for( i = 0; i < NUM_MESSAGES; i++ ) {
        pthread_join( threads[i], NULL );
    }

    pthread_exit( NULL );
}

我猜这个问题与参数指针有关。我试图锁定不同的部分,但没有成功。

4

3 回答 3

4

您正在传递主线程不断变化i的变量地址。所以你受调度的摆布:在你的线程有机会运行之前有人会改变吗?i

相反,您可以尝试直接传递字符串,从而大大简化代码:

rc = pthread_create( &threads[i], NULL, PrintHello, messages[i]);

void *PrintHello(void *arg)
{
    char *msg = arg;
    printf("%s\n", msg);

    return NULL;
}

还有另一种更糟糕的选择,您将实际值i作为参数(而不是它的地址)传递。

于 2012-07-10T06:57:28.433 回答
0

这是一个典型的race情况。
确切的说,新线程创建后,线程的执行顺序决定了程序的结果。有两种情况:

  1. 当线程函数PrintHello在下一个增量i++和线程分配之前执行void * argument = (void*) &i;main,它会输出您期望的内容。

  2. 当新线程PrintHello已创建但直到下一个线程中i++执行时才被调度main。在这种情况下,您argument在线程函数中的引用,即message_num = *((int *) messageid);不是您所期望的。

对此的解决方案是动态分配(使用mallocargument,并free在使用后将它们放在线程函数中。

于 2012-07-10T07:08:11.510 回答
0

将标量整数参数传递给线程函数的一种方法是(ab-)使用 C99 标准第 6.3.2.3 节中的以下文本:

(5) 整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

除了第二句的最后一部分,以下代码应该适用于大多数系统:

int int_val;
...
pthread_create(..., ..., thread_func, (void *)int_val);

然后thread_func将其转换回整数:

void *thread_func (void *data)
{
    int int_arg = (int)data;
    ...
}
于 2012-07-10T08:43:33.120 回答