2013-11-28 2 views
3

Я работаю над следующей функцией. Эта функция должна создавать n потоков. Также он должен распечатать значок дочернего потока. Но на данный момент я немного смущен. Когда я выполняю его и, например, создаю 5 потоков, он все время возвращает один и тот же файл. Насколько я понял, tid - это идентификатор потока вызывающего. Один и тот же вызывающий абонент вызывает все эти потоки или что-то не так. Вот код:C - Создание n потоков

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.

Но почему я получаю четыре раза один и тот же размер? Что я сделал не так? Я был бы признателен, если бы кто-нибудь мог объяснить мне, что пошло не так.

+0

Это не ваш фактический код. Ref 'pthread_creation' – Erik

+1

Также:' (void * (*) (void *)) 'what-the-cast ?! – Kninnug

+0

Вы вызываете 'syscall (SYS_gettid)' из основного потока, а не за созданные вами новые потоки ... – Dmitri

ответ

4

Причина, по которой вы получаете одинаковый 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); 
} 

В ab ove, мьютекс и ожидание состояния необходимы, чтобы убедиться, что основной поток не пытается распечатать TID до тех пор, пока новый поток не сможет его установить. Основной поток запускает новый, а затем ждет, и новый сигнал потока, когда он будет хранить TID, поэтому основной поток может продолжаться.

+0

хороший ответ, однако эта строка «if (pthread_create (& thread, NULL, foo, & threadId))« должно быть », если (pthread_create (& thread, NULL, foo, (void *) & threadId))». Обратите внимание, что листинг – splunk

+0

@GreenMamba. Прототип 'pthread_create()' 'указывает 'void *', поэтому он должен быть неявно преобразован в любом случае ... приведение не требуется. – Dmitri

1

В целом заинтересованы в трех элементах информации: идентификатор процесса, идентификатор потока и идентификатор потока pthreads. Все вызовы pthread являются самодостаточными, поскольку они используют их собственные идентификаторы потоков. Идентификаторы процессов и идентификаторы потоков os могут быть важны по причинам, выходящим за пределы API pthreads.

Идентификаторы Pthread сообщаются pthread_create и pthread_self, первый сообщает о его созданной нити, а последний, ну, сам. В противном случае это ситуация с курицей и яйцом. Один поток не может запросить другой поток, каков его идентификатор, если он уже не знает, что такое его идентификатор. Если это важно, то для его создания должен быть создан глобальный список, некоторые 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); 
} 
+0

С одной стороны, этот код позволяет потокам запускаться одновременно и сохраняет отдельную структуру для каждого, что хорошо ... но это также не мешает основному потоку (или другому) пытаться использовать данные до того, как они будут действительны , – Dmitri

+0

Он также не мешает подростковой беременности или обучению кого-то писать свою первую нить pgm с обучением использованию переменных условий. – Duck

+0

@ Duck: У меня вопрос к pthread_join. То, как вы его называете, находится в отдельном цикле после создания всех потоков. Но какая разница, если бы вы вызвали pthread_join в первом цикле? – tumbler

Смежные вопросы