c ++ pthread многопоточность для 2 x Intel Xeon X5570, четырехъядерных процессоров на экземпляре Amazan EC2 HPC Ubuntu - PullRequest
0 голосов
/ 20 ноября 2011

Я написал программу, которая использует многопоточность для параллельных вычислений.Я проверил, что в моей системе (OS X) он максимально использует оба ядра одновременно.Я просто перенес его в Ubuntu без каких-либо модификаций, потому что я написал его с учетом этой платформы.В частности, я запускаю образ Canonical HVM Oneiric на кластере Amazon EC2, работающем в 4x больших экземплярах.Эти машины оснащены двумя четырехъядерными процессорами Intel Xeon X5570.

К сожалению, моя программа не выполняет многопоточность на компьютере EC2.Запуск более 1 потока фактически немного замедляет вычисления для каждого дополнительного потока.Запуск top во время работы моей программы показывает, что при инициализации более 1 потока системный% потребления ЦП приблизительно пропорционален количеству потоков.Только с 1 потоком% sy составляет ~ 0.1.В любом случае пользователь% никогда не поднимается выше ~ 9%.

Ниже приведены разделы моего кода, относящиеся к потокам

const int NUM_THREADS = N;    //where changing N is how I set the # of threads

void Threading::Setup_Threading()
{
    sem_unlink("producer_gate");
    sem_unlink("consumer_gate");
    producer_gate = sem_open("producer_gate", O_CREAT, 0700, 0);           
    consumer_gate = sem_open("consumer_gate", O_CREAT, 0700, 0);
    completed   = 0;
    queued      = 0;            

    pthread_attr_init (&attr);
    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
}

void Threading::Init_Threads(vector <NetClass> * p_Pop)
{

    thread_list.assign(NUM_THREADS, pthread_t());        
    for(int q=0; q<NUM_THREADS; q++)
        pthread_create(&thread_list[q], &attr, Consumer, (void*) p_Pop );
}

void* Consumer(void* argument)
{

    std::vector <NetClass>* p_v_Pop = (std::vector <NetClass>*) argument ;

    while(1)
    {
        sem_wait(consumer_gate);
        pthread_mutex_lock (&access_queued);
        int index = queued;                         
        queued--;
        pthread_mutex_unlock (&access_queued);

        Run_Gen(  (*p_v_Pop)[index-1] );

        completed--;
        if(!completed)                  
            sem_post(producer_gate);
    }
}

main()
{
    ...
    t1 = time(NULL);
    threads.Init_Threads(p_Pop_m);
    for(int w = 0; w < MONTC_NUM_TRIALS ; w++)
    {
        queued = MONTC_POP;
        completed = MONTC_POP;

        for(int q = MONTC_POP-1 ; q > -1; q--) 
            sem_post(consumer_gate);

        sem_wait(producer_gate);

    }
    threads.Close_Threads();
    t2 = time(NULL);
    cout << difftime(t2, t1);
    ...
}

1 Ответ

2 голосов
/ 20 ноября 2011

Хорошо, просто угадайте. Существует простой способ преобразовать ваш параллельный код в последовательный. Например:

thread_func:
   while (1) {
     pthread_mutex_lock(m1);
     //do something
     pthread_mutex_unlock(m1);
     ...
     pthread_mutex_lock(mN);
     pthread_mutex_unlock(mN);

Если вы запустите такой код в нескольких потоках, вы не увидите никакого ускорения из-за использования мьютекса. Код будет работать как последовательный, а не как параллельный. Только один поток будет работать в любой момент.

Плохо то, что вы не можете использовать мьютекс в простоте вашей программы, но все равно есть такая ситуация. Например, вызов «malloc» может вызвать использование mutex, где во время выполнения «C» вызов «write» может вызвать использование mutex где-нибудь в ядре Linux. Даже вызов gettimeofday может вызвать блокировку / разблокировку mutex (и они вызывают, если рассказать о Linux / glibc).

Вы можете иметь только один мьютекс, но проводить под ним много времени, и это может вызвать такое поведение.

И поскольку мьютекс может использоваться где-то в ядре и во время выполнения C / C ++, вы можете увидеть различное поведение в разных ОС.

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