4

我正在研究以下功能。这个函数应该创建 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

总而言之,该函数应该打印>i< >tid<>tid<表示孩子的 TID,>i<从 1 运行到 n。

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

4

2 回答 2

3

您为每个线程获得相同 TID 的原因是您每次都syscall(SYS_gettid)从主线程调用,而不是从您创建的新线程中调用。您需要从线程函数内部调用它,然后提供一种方法将信息传递回主线程(如果需要)。

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

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

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 */
};

然后将您的线程函数更改为锁定、设置和发出信号(并移动它,使其声明在之前 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函数以初始化/清理结构成员并在线程设置它后获取 TID:

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);
}

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

于 2013-11-29T00:54:27.010 回答
0

人们通常感兴趣的信息有 3 条:进程 id、线程 id 和 pthreads 线程 id。所有pthread调用都是自包含的,因为它们在自己的线程 ID 上使用。由于 pthreads API 之外的原因,进程 ID 和操作系统线程 ID 可能很重要。

Pthread id 由pthread_createandpthread_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);
}
于 2013-11-29T02:43:35.577 回答