C ++ - не могу понять, как считать потоки с мьютексом - PullRequest
0 голосов
/ 09 декабря 2018

Я кодирую многопоточную сортировку слиянием в C ++.Контекст: пользователь запускает программу с соответствующими флагами, например, "./mergeSort 100 -t 20"

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

Для подсчета количества потоков Iиспользовать глобальную переменную number_of_units с блокировкой мьютекса, но я просто не могу, насколько я понимаю, сделать это правильно.

Стандартная функция сортировки слиянием печатает текст "стандарт", а функция многопоточности выводит "new thread # "# с числом новых потоков, которые программа все еще может создать.Я уменьшаю счетчик каждый раз, когда начинаю новую тему.Вот блок main ():

cout << "array: ";
printArray(nums);
cout << endl;
mergeSortDirector(sort, nums, 0, nums.size() - 1);
cout << endl << "sorted array: ";
printArray(nums);

mergeSortDirector просто перенаправляет программу на правильную сортировку изначально, в данном случае на mergeSortThread:

void mergeSortThread(vector<int> &nums, int beg, int end) {

    cout << "new thread " << *number_of_units << endl;

    int mid;

    thread half1;
    thread half2;

    if (beg < end) {
        mid = (beg + end) / 2;

        if(*number_of_units > 1) {

            *number_of_units -= 2;
            mtx.lock();
            half1 = thread(mergeSortThread, std::ref(nums), beg, mid);
            mtx.unlock();
            mtx.lock();
            half2 = thread(mergeSortThread, std::ref(nums), mid + 1, end);
            mtx.unlock();

            half1.join();
            half2.join();

        } else if(*number_of_units == 1) {

            *number_of_units--;
            mtx.lock();
            half1 = thread(mergeSortThread, std::ref(nums), beg, mid);
            mtx.unlock();
            mergeSort(nums, mid + 1, end);

            half1.join();

        } else {
            mergeSort(nums, beg, mid);
            mergeSort(nums, mid + 1, end);
        }

        merge(nums, beg, mid, end);
    }
}

и стандартный mergeSort:

void mergeSort(vector<int> &nums, int beg, int end) {

    cout << "standard" << endl;

    int mid;

    if (beg < end) {
        mid = (beg + end) / 2;

        mergeSort(nums, beg, mid);
        mergeSort(nums, mid + 1, end);

        merge(nums, beg, mid, end);
    }
}

Вывод программы (с 15 случайными числами и максимум 10 нитями):

array: 660919 974282 721803 971892 908195 137470 226270 609453 19612 988775 652618 298558 125993 598676 489395 

new thread 10
new thread 8
new thread 6
new thread 4
new thread 2
new thread 0
standard
standard
standard
standard
standard
standard
new thread 0
standard
standard
standard
standard
new thread 0
standard
standard
new thread 0
standard
standard
new thread 0
standard
standard
new thread 0
standard
standard

sorted array: 19612 125993 137470 226270 298558 489395 598676 609453 652618 660919 721803 908195 971892 974282 988775 

Проблема в том, что создаются новые потоки после того, как счетчик достигает нуля... Кто-нибудь знает, как я могу это остановить?Я предполагаю, что это только мое расположение блокировок мьютекса ...

1 Ответ

0 голосов
/ 09 декабря 2018

Вы не блокируете мьютекс вокруг точки, где вы изменяете или читаете *number_of_units.Поместите блокировки вокруг этих применений.

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

Вы должны также использовать std::lock_guard или std::unique_lock вместо прямой блокировки мьютекса.

std::unique_lock lock(mtx);
if(*number_of_units > 1) {

    *number_of_units -= 2;
    lock.unlock();
    [...]

} else if(*number_of_units == 1) {

    *number_of_units--;
    lock.unlock();
    [...]
} else {

    lock.unlock();
    [...]
}

Если вы неиспользуя C ++ 17, вам нужно будет указать тип мьютекса для std::unique_lock, например std::unique_lock<std::mutex>.

...