Максимальное количество одновременных потоков в std :: thread - PullRequest
0 голосов
/ 01 мая 2019

Я пытаюсь понять несколько базовых понятий в std::thread, в которых я все еще не уверен.Основной вопрос:

что на самом деле происходит, когда я превышаю значение std::thread::hardware_concurrency(), как я это делал ниже?

Я знаю, что метод это просто подсказка, но в этом случае 8 должно быть точным.Я не вижу предупреждений или ошибок, так что же на самом деле происходит?

Я подозреваю, что это как-то связано с моим непониманием join() и detach(), что приводит меня ко второму вопросу.

Я знаю, что если я раскручиваю потоки без join() или detach(), я получу ошибки во время выполнения.Как я понял из чтения и наблюдений, join() заставляет поток блокироваться до тех пор, пока он не завершит выполнение, в то время как detach() делает в основном обратное, позволяя потоку дичать до завершения, потенциально открывая банку с червями, если этопоток не завершается сам по себе.

Исходя из того, что я заметил, кажется, что использование join() и detach() являются взаимоисключающими.Это неправильно?Зачем мне когда-либо использовать join() и detach() в одной и той же теме?

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

#include <ctime>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>

std::vector<unsigned> getNumbers(unsigned n)
{
    std::vector<unsigned> out;
    while(n > 0)
    {
        out.push_back(rand());
        n--;
    }
    return out; 
}

int main() {
    srand(time(nullptr));
    std::vector<std::thread> threads;
    unsigned maxThreads = std::thread::hardware_concurrency();
    std::cout << "Max threads: " << maxThreads << std::endl;

    unsigned tooManyThreads = maxThreads + 5;

    for(auto i = 0; i < tooManyThreads; i++)
    {
        threads.push_back(std::thread(getNumbers,(rand() % 10000 + 1)));
        std::cout << "Starting thread " << i << " (" 
            << threads.back().get_id() << ")" << std::endl;
        threads.back().detach();
    }

    for(auto i = 0; i < tooManyThreads; i++)
    {   
        if(threads.at(i).joinable())
        {
            threads.at(i).join();
            std::cout << "Joining " << i << std::endl;
        }
    }
    return 0;
} 

Ответы [ 2 ]

2 голосов
/ 01 мая 2019

В любой момент времени на вашем компьютере запущено несколько тысяч потоков.Большинство из них происходят из других программ или процессов, из которых сотни или тысячи работают в фоновом режиме.(Вы можете увидеть их, если откроете TaskManager в Windows или наберете htop в командной строке Linux).

Так что же такое std::thread::hardware_concurrency?Это количество потоков, которые могут выполняться одновременно.Если у вас 8 логических ядер, вы можете одновременно выполнять только 8 потоков.Все остальные потоки «приостановлены», по крайней мере, до тех пор, пока не наступит их очередь.

Это может звучать как противоречие: как можно иметь тысячи потоков без тысяч ядер?Ответ заключается в том, что операционная система планирует потоки.Каждый активный поток запускается по очереди, и это происходит достаточно быстро, так что люди не замечают задержек, но эти потоки фактически не выполняются одновременно.

По сути, std::thread::hardware_concurrency говорит вам о максимально возможном ускоренииот использования потоков.Если у вас 8 ядер, максимальная скорость параллелизации с использованием потоков составляет 8x.Можно запускать больше потоков, чем это, и многие программы делают это, потому что они разработаны так, чтобы разные потоки обрабатывали задачи разных типов (например, один поток может читать / записывать файлы, а другой поток может управлять графическим интерфейсом, а другой поток может обрабатыватьв фоновом режиме, и другой поток может общаться с сетью), но на самом деле это не сделает вашу программу работать быстрее

2 голосов
/ 01 мая 2019

Вы, похоже, не понимаете, что означает «нить» в этом контексте. Существует два вида потоков: std::thread - это программное обеспечение поток , а std::thread::hardware_concurrency() возвращает количество аппаратного обеспечения потоков .

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

...