Странный порядок выполнения потоков? - PullRequest
3 голосов
/ 09 июля 2011

Я написал небольшую программу, чтобы увидеть количество накладных расходов, необходимых для создания потока.

Вот программа (я написал ее быстро, поэтому она не самая лучшая):

#include <iostream>
#include <pthread.h>

void * lala(void * cake) {
 int * hi = (int *)cake;
 std::cout << *hi << '\n';
}

int main(void) {
 pthread_t thread;
 for (int i = 0;i < 10000;i = i + 1) {
  pthread_create(&thread,0,lala,&i);
 }
}

Он в основном запускает 10000 потоков и передает им их номер потока, и каждый поток выводит свой номер.

Выходные данные меняются каждый раз, когда я запускаю программу, однако я заметил, что была одна часть, которая никогда не менялась:

В конце вывода я всегда нахожу это:

...
9994
9995
9996
9997
9998
9999
0

Что означает, что первый поток завершает последний ...

Итак, друзья мои, есть ли у кого-нибудь возможное объяснение этому явлению?

Ответы [ 4 ]

9 голосов
/ 09 июля 2011

Во-первых, вы передаете адрес локальной переменной в поток, который постоянно меняется.Таким образом, когда поток получает время для чтения, содержимое i уже будет изменено.Почему вы не можете просто передать i вместо &i, где переменная составляет всего 4 байта (то есть соответствует указателю)?

Во-вторых, вас не должно беспокоить, как ОС планирует ваши потоки.

4 голосов
/ 09 июля 2011

Ваш код печатает грязные данные. Там нет барьера памяти, поэтому данные буквально мусор. Вдобавок ко всему, вы не ждете завершения потоков, поэтому есть большая вероятность, что процесс будет прерван до того, как вы запустите все потоки. Чтобы достичь (более или менее) того, что вы хотите, попробуйте что-то вроде этого:

#include <iostream>
#include <pthread.h>

void * lala(void * cake) {
 int * hi = (int *)cake;
 std::cout << *hi << '\n';
}

int main(void) {
 int data[10000];
 pthread_t t[sizeof (data) / sizeof (data[0])];
 for (int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
 {
   data[i] = i;
 }

 for (int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
 {
  pthread_create(&t[i], 0, lala, &data[i]);
 }

  for (int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
 {
  pthread_join (t[i], NULL);
 }

}

И да, процессор не CUDA. Создание темы очень и очень дорого. Обычно вам лучше использовать однопоточное приложение, если вы действительно не знаете, что делаете. 95% многопоточных программ, которые я видел, скорее страдают от истощения потоков, чем от повышения производительности.

В любом случае, удачи!

3 голосов
/ 09 июля 2011

Как указал Аджай, вы передаете указатель на локальную переменную, которая постоянно меняется, и как только она выходит из области видимости (когда завершается for), доступ к ней является неопределенным поведением.

В любом случае, вы должны передать указатель на переменную, выделенную в куче, вашему потоку. Вы можете получить это с malloc() или new. Например:

void * lala(void * cake) {
    int hi = *(static_cast<int *>(cake));
    delete cake; //we don't need it anymore, delete to avoid a leak

    std::cout << hi << '\n';
}

int main(void) {
    pthread_t thread;

    for (int i = 0;i < 10000;i = i + 1) {
        int * pie = new int;
        *pie = i;
        pthread_create(&thread,0,lala,pie);
    }
}
2 голосов
/ 09 июля 2011

Это сильно зависит от реализации планировщика ядра, а также, возможно, от библиотеки pthread - и порядок выполнения потоков никогда не гарантируется.Для ускорения нормального использования pthreads сделано много оптимизаций, которых нет в вашем примере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...