Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 16:49
Оценка:
Привет!

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

Появились вопросы. В винде я обычно использовал CriticalSection — она позволяет уже залочившему потоку многократно делать лок без блокирования. Думал, std::mutex — это то, что мне нужно, но нет: If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. А я не хочу парится об этом, и помнить, какая функция у меня лочит, а какая — нет.

Далее. В винде есть Events или как-то так, могут быть в сигнальном и несигнальном состоянии. Вроде бы std::binary_semaphore похож на то, что мне нужно, но не уверен. Как получить на нем семантику SetEvent/ResetEvent/WaitFor?

Ну и сам std::thread. Что-то не понятно, можно ли и как ему подсунуть нестатическую функцию класса. В винде и в POSIX решалось через статический переходник, адрес объекта передавался через void* параметр. Тут аналогично надо приседать или есть варианты получше?

ЗЫ Тыщу лет многопоточки не писал, да и в новых плюсиках не очень ориентируюсь, звиняйте за глупые вопросы

ЗЗЫ Может, часть из того что нужно можно на атомиках сделать? Или это плохая идея?
Отредактировано 06.02.2023 16:51 пффф . Предыдущая версия .
Re: Многопоточность в современных плюсиках
От: Dair Россия https://dair.spb.ru
Дата: 06.02.23 17:08
Оценка: 2 (1) +2
Здравствуйте, пффф, Вы писали:

Что знаю, скажу, остальное не делал.

П>Появились вопросы. В винде я обычно использовал CriticalSection — она позволяет уже залочившему потоку многократно делать лок без блокирования. Думал, std::mutex — это то, что мне нужно, но нет: If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. А я не хочу парится об этом, и помнить, какая функция у меня лочит, а какая — нет.


Если какая функция лочит и потом анлочит, то recursive_mutex вроде то что надо.
Сколько локов — столько и анлоков.

П>Ну и сам std::thread. Что-то не понятно, можно ли и как ему подсунуть нестатическую функцию класса. В винде и в POSIX решалось через статический переходник, адрес объекта передавался через void* параметр. Тут аналогично надо приседать или есть варианты получше?


Лямбда, например?

std::thread t([](){
    std::cout << "thread function\n";
});
Re: Многопоточность в современных плюсиках
От: kov_serg Россия  
Дата: 06.02.23 17:17
Оценка: 32 (4)
Здравствуйте, пффф, Вы писали:

П>Привет!


П>ЗЫ Тыщу лет многопоточки не писал, да и в новых плюсиках не очень ориентируюсь, звиняйте за глупые вопросы

Почитайте на досуге
Re[2]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:19
Оценка:
Здравствуйте, Dair, Вы писали:

D>Если какая функция лочит и потом анлочит, то recursive_mutex вроде то что надо.

D>Сколько локов — столько и анлоков.

Да, точно, оно самое. Только вопрос такой — CriticalSection вроде как легковесный, спин лок, а мьютекс — это обычно сразу ядрёный вызов. В принципе, сейчас-то наплевать, но в целях саморазвития, есть что-то подобное лёгкое?


П>>Ну и сам std::thread. Что-то не понятно, можно ли и как ему подсунуть нестатическую функцию класса. В винде и в POSIX решалось через статический переходник, адрес объекта передавался через void* параметр. Тут аналогично надо приседать или есть варианты получше?


D>Лямбда, например?


D>
D>std::thread t([](){
D>    std::cout << "thread function\n";
D>});
D>


Наверное да, но тогда имхо и std::function должен проканать, а он вроде умеет в методы экземпляра объекта. Но я просто никогда этим не пользовался
Re[2]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:22
Оценка:
Здравствуйте, kov_serg, Вы писали:

П>>ЗЫ Тыщу лет многопоточки не писал, да и в новых плюсиках не очень ориентируюсь, звиняйте за глупые вопросы

_>Почитайте на досуге

О, спасибо, на досуге почитаю. А сейчас код колбасить надо, может подскажешь по-быстрому?
Re[3]: Многопоточность в современных плюсиках
От: vopl Россия  
Дата: 06.02.23 17:32
Оценка: 2 (1)
Здравствуйте, пффф, Вы писали:

П>Здравствуйте, Dair, Вы писали:


D>>Если какая функция лочит и потом анлочит, то recursive_mutex вроде то что надо.

D>>Сколько локов — столько и анлоков.

П>Да, точно, оно самое. Только вопрос такой — CriticalSection вроде как легковесный, спин лок, а мьютекс — это обычно сразу ядрёный вызов. В принципе, сейчас-то наплевать, но в целях саморазвития, есть что-то подобное лёгкое?


std::mutex и winapi-mutex это существенно разные вещи, не нужно из путать. std::mutex обычно реализован через winapi-CriticalSection, в живую все это увидеть можно примерно тут
https://github.com/ojdkbuild/tools_toolchain_vs2017bt_15936/blob/db988fa6fd0e2c972d816f1072e59e2cf1680126/VC/Tools/MSVC/14.16.27023/include/mutex#L96
https://github.com/ojdkbuild/tools_toolchain_vs2017bt_15936/blob/db988fa6fd0e2c972d816f1072e59e2cf1680126/VC/Tools/MSVC/14.16.27023/include/mutex#L36
https://github.com/ojdkbuild/tools_toolchain_vs2017bt_15936/blob/db988fa6fd0e2c972d816f1072e59e2cf1680126/VC/Tools/MSVC/14.16.27023/crt/src/stl/mutex.c#L41
и далее

П>>>Ну и сам std::thread. Что-то не понятно, можно ли и как ему подсунуть нестатическую функцию класса. В винде и в POSIX решалось через статический переходник, адрес объекта передавался через void* параметр. Тут аналогично надо приседать или есть варианты получше?


D>>Лямбда, например?


D>>
D>>std::thread t([](){
D>>    std::cout << "thread function\n";
D>>});
D>>


П>Наверное да, но тогда имхо и std::function должен проканать, а он вроде умеет в методы экземпляра объекта. Но я просто никогда этим не пользовался


на метод можно выйти так
myObjPtr = ...
std::thread t([myObjPtr](){
    myObjPtr->myMethod();
});
Re: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:39
Оценка:
Здравствуйте, пффф, Вы писали:

Да, и ещё.

Мне надо сделать поток и два сигнала. Один сигнал — что для потока есть работа, воркер на нем спит, основной поток сигналит, воркер просыпается, сбрасывает сигнал, делает работу, и опять засыпает, или, если второй стоп-сигнал тоже активен — завершает работу. Второй сигнал — что воркеру надо завершиться — ставим его в сигнальное состояние, затем будим поток по первому сигналу, и ждём завершения.

1) Нормальная ли логика, или я что-то пропустил?
2) Не очень понятно, как это все инициализировать, при условии, что это всё члены одного класса, и поток будет выполнять один из методов этого класса. Как это всё правильно сделать?
Re[3]: Многопоточность в современных плюсиках
От: ArtDenis Россия  
Дата: 06.02.23 17:39
Оценка:
Здравствуйте, пффф, Вы писали:

П>О, спасибо, на досуге почитаю. А сейчас код колбасить надо, может подскажешь по-быстрому?


Если по-быстрому, то лучше писать так как привык (дёргая низкоуровневые API)
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[4]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:43
Оценка:
Здравствуйте, vopl, Вы писали:

П>>Наверное да, но тогда имхо и std::function должен проканать, а он вроде умеет в методы экземпляра объекта. Но я просто никогда этим не пользовался


V>на метод можно выйти так

V>
V>myObjPtr = ...
V>std::thread t([myObjPtr](){
V>    myObjPtr->myMethod();
V>});
V>


Мне бы всё в конструкторе разрулить. Как я понял, std::thread'у надо указать функцию, которую он сразу начнёт выполнять. И нет никакого неактивного состояния, чтобы чтобы задать функцию потока, но отложить выполнение до вызова .run(), и нет возможности создать объект потока без функции, и потом запустить — .run(func)
Re[4]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:44
Оценка:
Здравствуйте, ArtDenis, Вы писали:

П>>О, спасибо, на досуге почитаю. А сейчас код колбасить надо, может подскажешь по-быстрому?


AD>Если по-быстрому, то лучше писать так как привык (дёргая низкоуровневые API)


Не хочу, хочу переносимо, а писать две реализации для WinAPI и POSIX — уже старый стал, ленивый
Re: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:48
Оценка:
Здравствуйте, пффф, Вы писали:

Правильно ли я понимаю, что std::lock_guard и std::scoped_lock — аналогичны, но второй может лочить пачки разнородных объектов, а первый — только один mutex_type мьютекс?
Re[4]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 17:50
Оценка:
Здравствуйте, vopl, Вы писали:

D>>>Если какая функция лочит и потом анлочит, то recursive_mutex вроде то что надо.

D>>>Сколько локов — столько и анлоков.

П>>Да, точно, оно самое. Только вопрос такой — CriticalSection вроде как легковесный, спин лок, а мьютекс — это обычно сразу ядрёный вызов. В принципе, сейчас-то наплевать, но в целях саморазвития, есть что-то подобное лёгкое?


V>std::mutex и winapi-mutex это существенно разные вещи, не нужно из путать. std::mutex обычно реализован через winapi-CriticalSection, в живую все это увидеть можно примерно тут


Могли бы отдельно спин-лок класс сделать, а не путать народ. В винде мьютекс можно шарить между процессами, а в плюсиках как с этим? Или такого нет?
Re[2]: Многопоточность в современных плюсиках
От: sergey2b ЮАР  
Дата: 06.02.23 18:04
Оценка:
Здравствуйте, пффф, Вы писали:

П>Здравствуйте, пффф, Вы писали:


П>Да, и ещё.


П>Мне надо сделать поток и два сигнала. Один сигнал — что для потока есть работа, воркер на нем спит, основной поток сигналит, воркер просыпается, сбрасывает сигнал, делает работу, и опять засыпает, или, если второй стоп-сигнал тоже активен — завершает работу. Второй сигнал — что воркеру надо завершиться — ставим его в сигнальное состояние, затем будим поток по первому сигналу, и ждём завершения.


я понимаю что это не по фуншую но работает под win and linux

https://github.com/neosmart/pevents/
Re[2]: Многопоточность в современных плюсиках
От: B0FEE664  
Дата: 06.02.23 18:04
Оценка:
Здравствуйте, kov_serg, Вы писали:

П>>ЗЫ Тыщу лет многопоточки не писал, да и в новых плюсиках не очень ориентируюсь, звиняйте за глупые вопросы

_>Почитайте на досуге

Полистал. Похоже, что если по такой книжке учиться, то хорошего кода не получится.
И каждый день — без права на ошибку...
Re: Многопоточность в современных плюсиках
От: DiPaolo Россия  
Дата: 06.02.23 18:16
Оценка:
Выше писал, что надо по-быстрому. Думаю, вот этого должно хватить для начала:

https://en.cppreference.com/w/cpp/thread/thread/thread
https://en.cppreference.com/w/cpp/thread/mutex
https://en.cppreference.com/w/cpp/thread/condition_variable

опционально:
https://en.cppreference.com/w/cpp/atomic/atomic

Почти везде есть примеры.

И вот еще основная страница со всеми темами про мультипоточность https://en.cppreference.com/w/cpp/thread.
Патриот здравого смысла
Re[3]: Многопоточность в современных плюсиках
От: kov_serg Россия  
Дата: 06.02.23 18:17
Оценка: 9 (2)
Здравствуйте, B0FEE664, Вы писали:

BFE>Полистал. Похоже, что если по такой книжке учиться, то хорошего кода не получится.

Так этож новое молодёжное. Если хочется хорошего есть https://github.com/taskflow/taskflow
Re: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 18:29
Оценка:
Здравствуйте, пффф, Вы писали:

А что-то типа виндового Event с авторесетом есть?
Re: semaphore в MSVC 2019 недоступен
От: пффф  
Дата: 06.02.23 18:36
Оценка:
Здравствуйте, пффф, Вы писали:

Вижуалка MSVC 2019 говорит:

The contents of <semaphore> are available only with C++20 or later.


У меня 17ые. Для 17ых с вижуалкой что можно использовать?
Re[5]: Многопоточность в современных плюсиках
От: vopl Россия  
Дата: 06.02.23 18:47
Оценка:
Здравствуйте, пффф, Вы писали:

П>Здравствуйте, vopl, Вы писали:


П>>>Наверное да, но тогда имхо и std::function должен проканать, а он вроде умеет в методы экземпляра объекта. Но я просто никогда этим не пользовался


V>>на метод можно выйти так

V>>
V>>myObjPtr = ...
V>>std::thread t([myObjPtr](){
V>>    myObjPtr->myMethod();
V>>});
V>>


П>Мне бы всё в конструкторе разрулить. Как я понял, std::thread'у надо указать функцию, которую он сразу начнёт выполнять. И нет никакого неактивного состояния, чтобы чтобы задать функцию потока, но отложить выполнение до вызова .run(), и нет возможности создать объект потока без функции, и потом запустить — .run(func)


Если я правильно понял..
class MyClass
{
public:
    MyClass()
    {
    }

    void run()
    {
        worker = std::thred{[this]{
            //и вызывай любые методы в этом потоке
        }};
    }

    ~MyClass()
    {
        if(worker.joinable()) worker.join();
    }
private:
    std::thread worker;
}

MyClass myObj;// теперь там внутри как бы есть работающий поток


А вообще, лучше такое не на форуме спрашивать а самому вот тут смотреть https://en.cppreference.com/w/cpp/thread/thread, там номенклатура методов представлена, сразу видно что поток может и чего не может.
Re[5]: Многопоточность в современных плюсиках
От: vopl Россия  
Дата: 06.02.23 18:51
Оценка:
Здравствуйте, пффф, Вы писали:

V>>std::mutex и winapi-mutex это существенно разные вещи, не нужно из путать. std::mutex обычно реализован через winapi-CriticalSection, в живую все это увидеть можно примерно тут


П>Могли бы отдельно спин-лок класс сделать, а не путать народ.

Да вроде никто и не путается, ты первый жалуешся

П>В винде мьютекс можно шарить между процессами, а в плюсиках как с этим? Или такого нет?

Нет.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.