C - 创建n个线程

时间:2013-11-28 23:08:00

标签: c linux pthreads pthread-join

我正在研究以下功能。这个函数应该创建n个线程。它也应该打印子线程的tid。但此刻我有点困惑。当我执行它并且例如我创建5个线程时,它会一直返回相同的tid。据我所知,tid是调用者的线程ID。同一个调用者是否调用了所有这些线程,或者我做错了什么。 这是代码:

void spawnThreads( unsigned int n) {
   int threads = n, ret = -1;
   pthread_t * thread = malloc(sizeof(pthread_t)*threads);
   pid_t tid;
   int i;
   for(i = 0; i < threads; i++) {
       ret = pthread_creation(&thread[i], NULL, (void *(*)(void *)) foo, NULL); // foo does not do anything

       if( ret != 0) {
           printf("pthread error!\n");
       }

       tid = syscall(SYS_gettid);
       printf("%d %d\n", i, tid);
       printf("I just created thread %d\n", i);

       pthread_join(thread[i],NULL);
}

void * foo(void) {
    return NULL;
}

例如,我得到以下输入 spawnThreads(4) 以下输出:

 0 2411
 I just created thread 0

 1 2411
 I just created thread 1

 2 2411
 I just created thread 2

 3 2411
 I just created thread 3

总之,该功能应打印&gt; i&lt; &GT; TID&LT; 即可。 &gt; tid&lt; 表示儿童的TID,&gt; i&lt; 从1运行到n。

但为什么我会得到相同tid的四倍?我做错了什么?如果有人能解释我出了什么问题,我将不胜感激。

2 个答案:

答案 0 :(得分:4)

您为每个线程获得相同TID的原因是您每次都从主线程调用syscall(SYS_gettid),而不是从您创建的新线程中调用struct s_threadId { pthread_mutex_t mtx; /* mutex & condition to allow main thread to wait for the new thread to set its TID */ pthread_cond_t cond; /* '' */ pid_t id; /* to hold new thread's TID */ int ready; /* to indicate when 'id' is valid, in case the condition wait gets interrupted */ }; 。您需要从线程函数内部调用它,然后提供一种方法将信息传递回主线程(如果需要)。

作为一种方法的例子(省略了一些错误检查):

创建一个结构来保存互斥锁,条件,TID和一个标志,以指示TID何时有效。

spawnThreads()

然后将您的线程函数更改为锁定,设置和发信号(并移动它以使其声明在 void *foo(void *arg) { struct s_threadId *thId = arg; /* Lock mutex... */ pthread_mutex_lock(&thId->mtx); /* Get and save TID and ready flag.. */ thId->id = syscall(SYS_gettid); thId->ready = 1; /* ..and signal main thread that we're ready */ pthread_cond_signal(&thId->cond); /* ..then unlock when we're done. */ pthread_mutex_unlock(&thId->mtx); /* ... */ return NULL; } 之前可见):

spawnThreads

...并修改你的void spawnThreads(unsigned int n) { pthread_t thread; /* reused for each thread, since they run 1 at a time */ /* struct to pass back TID */ struct s_threadId threadId; pthread_cond_init(&threadId.cond, NULL); /* init condition */ pthread_mutex_init(&threadId.mtx, NULL); /* init mutex */ int i; for (i = 0; i < n; i++) { /* lock mutex *before* creating the thread, to make the new thread wait until we're ready before signaling us */ pthread_mutex_lock(&threadId.mtx); /* clear ready flag before creating each thread */ threadId.ready = 0; /* create threads and pass address of struct as argument */ if (pthread_create(&thread, NULL, foo, &threadId)) { printf("pthread error!\n"); } else { /* Wait on the condition until the ready flag is set */ while (!threadId.ready) { pthread_cond_wait(&threadId.cond, &threadId.mtx); } /* Now we have the TID... */ printf("%d %d\n", i, threadId.id); printf("I just created thread %d\n", i); } /* ..and unlock the mutex when done. */ pthread_mutex_unlock(&threadId.mtx); pthread_join(thread, NULL); } /* When we're completely done with the struct we need to clean up the mutex and condition variable */ pthread_mutex_destroy(&threadId.mtx); pthread_cond_destroy(&threadId.cond); } 函数来初始化/清理struct成员并在线程设置后获取TID:

{{1}}

在上面,需要互斥和条件等待,以确保主线程不会尝试打印TID,直到新线程有机会设置它。主线程启动新线程然后等待,新线程在完成存储TID时发出信号,以便主线程可以继续。

答案 1 :(得分:1)

有三个人通常感兴趣的信息:进程ID,线程ID和pthreads线程id。所有pthread调用都是自包含的,因为它们使用自己的线程ID。由于pthreads API之外的原因,进程ID和os线程ID可能很重要。

Pthread ID由pthread_createpthread_self报告,前者报告它创建的线程,后者报告本身。否则就是鸡蛋和鸡蛋的情况。一个线程不能向另一个线程询问它的id是什么,除非它已经知道它的id是什么。如果这很重要,必须建立一些机制,全局列表,一些IPC等来实现它。

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <string.h>

typedef struct
{
    int       i;
    pid_t     pid;   // linux pid
    pid_t     tid;   // linux thread id
    pthread_t ptid;  // pthreads tid    
} data;

void *foo(void *args)
{
    data *p = (data *) args;

    p->pid  = getpid();
    p->tid  = syscall(SYS_gettid);
    p->ptid = pthread_self();

    return(p);
}

void spawnThreads(unsigned int numThreads)
{
    int ret;
    pthread_t *tids = malloc(sizeof(pthread_t) * numThreads);

    int i;

    for (i = 0; i < numThreads; i++)
    {
        data *dp = malloc(sizeof(data) * numThreads);
        memset(dp, '\0', sizeof(*dp));

        dp->i = i;

        ret = pthread_create(&tids[i], NULL, foo, (void *) dp);

        if ( ret != 0)
            perror("pthread create error");
    }

    for (int i = 0; i < numThreads; ++i)
    {
        data *status;

        ret = pthread_join(tids[i], (void *) &status);

        if ( ret != 0)
            perror("pthread join error");
        else
        {
            printf("thread num %d joined and reports pthreadId of %lu "
                   "process pid of %d and linux tid of %d\n",
                   status->i, status->ptid, status->pid, status->tid);

            free(status);
        }
    }

    free(tids);
}

int main(int argc, char *argv[])
{
    printf("main thread reports pthreadId of............ %lu "
           "process pid of %d and linux tid of %ld\n",
           pthread_self(), getpid(), syscall(SYS_gettid));

    spawnThreads(5);

    return (0);
}