Измерение эффективности ожидания Mutex и Busy - PullRequest
1 голос
/ 26 февраля 2012

Программа должна создать несколько потоков, где каждый поток увеличивает общую переменную на 10000, используя цикл for, который увеличивает ее на 1 в каждой итерации.Требуются обе версии: мьютекс-блокировка и спин-блокировка (ожидание занятости).Согласно тому, что я узнал, мьютексная версия должна работать быстрее, чем спин-блокировка.Но то, что я реализовал, дало мне противоположный ответ ...

Это дополнение каждого потока в версии мьютекса:

void *incr(void *tid)
{
    int i;
    for(i = 0; i < 10000; i++)
    {
        pthread_mutex_lock(&the_mutex);     //Grab the lock
        sharedVar++;    //Increment the shared variable
        pthread_mutex_unlock(&the_mutex);   //Release the lock
    }
    pthread_exit(0);
}

И это реализация в версии спин-блокировки:

void *incr(void *tid)
{
    int i;
    for(i = 0; i < 10000; i++)
    {
        enter_region((int)tid);  //Grab the lock
        sharedVar++;        //Increment the shared variable
        leave_region((int)tid);  //Release the lock
    }
    pthread_exit(0);
}
void enter_region(int tid)
{
    interested[tid] = true;     //Show this thread is interested
    turn = tid;     //Set flag
    while(turn == tid && other_interested(tid));    //Busy waiting
}
bool other_interested(int tid)    //interested[] is initialized to all false
{
    int i;
    for(i = 0; i < tNumber; i++)
        if(i != tid)
            if(interested[i] == true)   //There are other threads that are interested
                return true;
    return false;
}
void leave_region(int tid)
{
    interested[tid] = false;    //Depart from critical region
}

Я также повторял процесс создания и запуска потоков в течение сотен раз, чтобы можно было различить время выполнения.Например, если tNumber равно 4, и я повторял программу 1000 раз, мьютекс займет у меня 2,22 секунды, а спин-блокировка - у меня 1,35 секунды.Разница увеличивается с увеличением tNumber.Почему это происходит?Мой код неверен?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2012

«Разница» в скорости заключается в том, что вы осуществляете синхронизацию, используя

interested[tid] = true;     //Show this thread is interested
turn = tid;     //Set flag
while(turn == tid && other_interested(tid));  

, которые являются последовательными операциями.Любой поток может быть прерван, пока он это делает, и следующий поток читает ошибочное состояние.

Это нужно сделать атомарно, используя либо compare-and-swap, либо test-and-set.Эти инструкции обычно предоставляются оборудованием.

Например, на x86 у вас есть xchg, cmpxchg/cmpxchg8b, xadd
Ваш тест может быть переписан как

while( compare_and_swap_atomic(myid,id_meaning_it_is_free) == false);

Проблема в том, что атомарность дорогая .

0 голосов
/ 26 февраля 2012

Код между enter_region и leave_region не защищен.

Вы можете доказать это, сделав его более сложным, чтобы убедиться, что он отключится сам.bools (чек) длиной 10000 настроил false.Сделайте код между вводом и уходом:

if (check[sharedVar]) cout << "ERROR" << endl;
else check[sharedVar++] = true;
...