Варианты запуска потоков



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



В С++ есть такое понятие - callable objects. Это просто сущности, которые можно вызвать. Это функции, лямбды, функторы, методы и так далее. Как можно единообразно вызывать все эти сущности? Сходу в голову ничего не приходит, но в стандартной библиотеке начиная с С++17 есть такая функция std::invoke. Вот ее сигнатура:



template< class F, class... Args>

std::invokeresultt<F, Args...> invoke(F&& f, Args&&... args) noexcept



И существуют правила, по которым эта функция парсит свои аргументы. Но не только она, а все сущности, которые как бы "вовлекают" в работу callable объект. Открывайте окна, потому что щас немного духоты будет.



Пусть INVOKE(f, t1, t2, ..., tN) - выражение, обозначающее вовлечение в работу функционального объекта f. Тогда:



Если f - указатель на метод класса T:

t1 - объект типа Т, или ссылка на объект типа Т,

или ссылка на наследника типа Т, то этот INVOKE превращается в (t1.*f)(t2, ..., tN).

t1 - ни что из перечисленного выше(то есть указатель на объект), то INVOKE превращается в ((*t1).*f)(t2, ..., tN).



Если N=1 и f - указатель на член класса:

t1 - объект типа Т, или ссылка на объект типа Т,

или ссылка на наследника типа Т, то этот INVOKE превращается в t1.*f.

t1 - ни что из перечисленного выше(то есть указатель на объект), то INVOKE превращается в (*t1).*f.



Во всех других случая INVOKE разворачивается в обычный вызов функции f(t1, t2, ..., tN).



То есть конструктор std::thread, который внутри себя дергает std::invoke, на основе вот этих простых правил и решает, что ему на самом деле передали и как себя дальше вести.



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



Так что создавайте потоки осознанно и так, как больше подходит именно в вашей ситуации. Потому что способов - тьма.



Stay versatile. Stay cool.



#multitasking