Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> pthread, снизить издержки на синхронизацию потоков, нужны советы, критика по функции потока 
V
    Опции темы
NoviceF
Дата 1.12.2012, 20:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Добрый вечер.

Ситуация следующая, есть учебно-развивающий проект, цель которого реализовать быструю сортировку в 2 и более потоков, при этом основная задача, чтобы производительность данной сортировки была не менее, чем на 50% быстрее однопоточной STL реализации sort.

Сортируем вектор, забитый 1млном случайных интов.

Алгоритм взять из умной книжки, и в однопоточном варианте к нему претензий нет, в условиях случайного заполнения массива работает в пределах до 10% медленнее std::sort, тут важно заметить, что значения меняются в небольшой диапазоне, в отличие от двухпоточного варианта, о чём напишу ниже.

Собственно, основная проблема в быстродействии функции потока, где точно сам не пойму. Узкие места - доступ к общим ресурсам, в данном случае это глобальный стек, ну и дальше посмотрите сами.

Очереди реализованы на std::stack. Логика работы следующая: есть глобальная очередь, до запуска потоков в неё помещаюся "координаты" отрезка, который нужно сортировать. Изначально это 0 и vector.size(). В целом ставится задача, чтобы в глобальной очереди, постоянно находился хотя бы 1 элемент, чтобы всегда была работа, для освободившегося потока.
Сначала проверяем пуста ли локальная и есть ли что-нибудь в глобальной очереди, если условия верны, забираем отрезок из глобальной очереди в локальную.
Далее сортируем локальную очередь до тех пор, пока в ней не будет 2+ элементов и, т.к. на данный момент глобальная очередь пуста, останавливаем сортировку, откладываем в глобальную очередь 1 отрезок, чтобы дать работу второму потоку.
После идут условия завершения работы, либо ожидания.
Работа завершается, если обе очереди пусти и все потоки, кроме данного, находятся в состоянии ожидания на переменной условия.
Либо, если очереди пусты, но есть ещё работающие потоки, поток переходит в ожидание на переменной условия.


Код

void * f(void * arg)
{
    SortingTask *sortingTask = (static_cast<SortingTask*> (arg));
    Manager &mn = *sortingTask->mn;
    std::stack<Coords> localDeq;

    while (1)
    {
        if (localDeq.empty() && !mn.globalDeq.empty()) ////// localdeq is empty
        {
            pthread_mutex_lock(&mn.mutexQue_);
            if (!mn.globalDeq.empty())
            {
                localDeq.push(mn.globalDeq.top());
                mn.globalDeq.pop();
            }
            pthread_mutex_unlock(&mn.mutexQue_);
        }

        while (!localDeq.empty())
        {
            Coords cd1 = localDeq.top();
            localDeq.pop();

            quicksort(mn.vec, &cd1.start, &cd1.end, &cd1.i);

            if (cd1.start < cd1.i - 1) localDeq.push(
                    Coords{cd1.start, cd1.i - 1, cd1.i}
            );
            if (cd1.i + 1 < cd1.end) localDeq.push(
                    Coords{cd1.i + 1, cd1.end, cd1.i}
            );
            if (mn.globalDeq.empty() && localDeq.size() > 1)
            {
                break;
            }
        }
        if (mn.globalDeq.empty() && localDeq.size() > 1)
        {
            pthread_mutex_lock(&mn.mutexQue_);
            if (mn.globalDeq.empty())
            {
                mn.globalDeq.push(localDeq.top());
                localDeq.pop();
                if (mn.waitOnCond_)
                {
                    pthread_cond_signal(&mn.cond);

                }
            }
            pthread_mutex_unlock(&mn.mutexQue_);
        }
        if (mn.globalDeq.empty() && localDeq.empty()) ///////// waiting cond
        {
            pthread_mutex_lock(&mn.mutexQue_);
            if (mn.globalDeq.empty() && localDeq.empty() ///////// exit cond
                    && mn.isOtherTreadsWait()) mn.exitThread();
            while (mn.globalDeq.empty() && !mn.isOtherTreadsWait())
            {
                ++mn.waitOnCond_;
                pthread_cond_wait(&mn.cond, &mn.mutexQue_);

                if (mn.jobEnd_)
                {
                    mn.exitThread();
                }
                --mn.waitOnCond_;
            }
            pthread_mutex_unlock(&mn.mutexQue_);
        }
    }
    return NULL;
}

bool Manager::isJobEnd()
{

    return jobEnd_;
}

void Manager::jobIsEnd()
{

    jobEnd_ = true;
}

bool Manager::isOtherTreadsWait()
{
    return waitOnCond_ == (threadsTotal_ - 1);
}

void Manager::exitThread()
{
    jobIsEnd();
    //    cout << "jobEnd" << endl; 
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutexQue_);
    pthread_exit(NULL);
}


В общем-то, эта функция работает и в 2 потока сортирует где-то на 30-40% быстрее std::sort, но иногда проскакивают результаты на 60-70% быстрее (скорость работы std::sort всегда примерно одинакова, +- 10 мс).. ну и такое положение дел говорит о том, что есть проблемы. Так как я их не вижу, прошу вас указать на них. И вообще буду рад любым советам по теме, как увеличить "скорость работы" данной функции, или же, как уменьшить использование мутексов/переменной условия и т.п.
PM MAIL   Вверх
NoviceF
Дата 2.12.2012, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Прикрутил таймер и потестил.. почему-то второй последующие потоки не стартуют, пока первый не закончит работу...

функция, которая запускает потоки выглядит так:

Код

void startAll(pthread_t *threads, int threadsCount, Manager &mn,
        SortingTask::dType type)
{
    SortingTask* tasks = new SortingTask [threadsCount];

    for (int i = 0; i < threadsCount; ++i)
    {
        tasks[i].id = i;
        tasks[i].mn = &mn;
        tasks[i].dataType = type;

        int status = pthread_create(&threads[i], NULL, f, &tasks[i]);
        if (status != 0)
        {
            cout << "thread starting failed" << endl;
        }
    }

    waitAll(threads, threadsCount);

    delete []tasks;
}


может проблема в ней и есть способ лучше поднимать потоки?

хотя это на винде под cygwin'ом.. ну бубунте вроде бы запускаются одновременно..  smile 

Это сообщение отредактировал(а) NoviceF - 2.12.2012, 09:56
PM MAIL   Вверх
bsa
Дата 3.12.2012, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 16
Всего: 196



NoviceF, открой для себя библиотеку boost::thread, а конкретнее, boost::thread_group - это то, что тебе нужно.
PM   Вверх
NoviceF
Дата 4.12.2012, 09:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(bsa @ 3.12.2012,  15:42)
NoviceF, открой для себя библиотеку boost::thread, а конкретнее, boost::thread_group - это то, что тебе нужно.

Да с удовольствием бы, но в условиях задачи использовать именно pthread :(
PM MAIL   Вверх
NoviceF
Дата 4.12.2012, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Хотя, наверное, попробую сделать альтернативную реализацию на бусте..
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0817 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.