Многопоточность в современных плюсиках
От: пффф  
Дата: 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 Россия  
Дата: 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, в живую все это увидеть можно примерно тут


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

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

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

Нет.
Re[6]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 18:55
Оценка:
Здравствуйте, vopl, Вы писали:

V>А вообще, лучше такое не на форуме спрашивать а самому вот тут смотреть https://en.cppreference.com/w/cpp/thread/thread, там номенклатура методов представлена, сразу видно что поток может и чего не может.


Да я смотрел, не совсем всё понятно.

Пораскинул, получается так: если мы хотим сделать изначально спящий поток, то просто конструируем без адреса функции: auto th = std::thread() (но на самом деле никакого потока не будет создано), если хотим сделать run(func), делаем th = std::thread(func), а вот чтобы при создании задать функцию потока, но отложить его запуск до лучших времён — такого нет
Re[6]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 19:41
Оценка: :))
Здравствуйте, vopl, Вы писали:

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

V>Нет.

Ну вот и путают. Классический мьютекс — это средство межпроцессного взаимодействия
Re[3]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 06.02.23 20:19
Оценка:
Здравствуйте, пффф, Вы писали:

П>CriticalSection вроде как легковесный, спин лок

Не, он сначала "спинает в гробу" а если спинал слишком долго тогда взыхает и переходит к более тяжёлому ожиданию.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[4]: Многопоточность в современных плюсиках
От: пффф  
Дата: 06.02.23 20:21
Оценка:
Здравствуйте, CreatorCray, Вы писали:


П>>CriticalSection вроде как легковесный, спин лок

CC>Не, он сначала "спинает в гробу" а если спинал слишком долго тогда взыхает и переходит к более тяжёлому ожиданию.

Да, спасибо, я в курсе, как и о том, что начиная с XP спин каунтер можно задавать
Re[2]: Многопоточность в современных плюсиках
От: Aquilaware  
Дата: 07.02.23 03:44
Оценка:
Здравствуйте, пффф, Вы писали:

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


В WinAPI для такого часто Event используют. В POSIX подход немного иной: обычно используют condition_variable. Смысл этого примитива в том, что каждый поток читает/меняет состояние внутри лока. После этого, можно делать такие вещи: если при чтении состояние не устраивает и нужно подождать другое, то делается wait. А другой поток может в локе ставить новое состояние и уведомлять того, кто ожидает с помощью notify.

Вот тут пример есть.

Condition variable это очень удобная вещь, намного более удобная чем просто event в большинстве случаев. С помошью сondition variable можно не только флаги ждать/ставить, но и потокобезопасно работать с очередями задач и вообще с любым другим состоянием. Event же работает только с одним битом, что является иногда полезным, но не универсальным решением.
Re[7]: Многопоточность в современных плюсиках
От: vopl Россия  
Дата: 07.02.23 05:23
Оценка:
Здравствуйте, пффф, Вы писали:

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


V>>А вообще, лучше такое не на форуме спрашивать а самому вот тут смотреть https://en.cppreference.com/w/cpp/thread/thread, там номенклатура методов представлена, сразу видно что поток может и чего не может.


П>Да я смотрел, не совсем всё понятно.


П>Пораскинул, получается так: если мы хотим сделать изначально спящий поток, то просто конструируем без адреса функции: auto th = std::thread() (но на самом деле никакого потока не будет создано), если хотим сделать run(func), делаем th = std::thread(func), а вот чтобы при создании задать функцию потока, но отложить его запуск до лучших времён — такого нет


Это слишком частный кейс для того чтобы его обобщать в стандартной библиотеке. Его достаточно просто получить при помощи комбинирования имеющихся средств.
#include <functional>
#include <thread>
#include <iostream>

struct DelayedStartThread : std::thread
{
    template <class F>
    DelayedStartThread(F&& f)
        : std::thread{}
        , _f{std::forward<F>(f)}
    {
    }

    void start()
    {
        std::thread::operator=(std::thread{move(_f)});
    }

    std::function<void()> _f;
};

int main()
{
    DelayedStartThread dst{[]{
        std::cout << "started" << std::endl;
    }};
    std::cout << "not started yet" << std::endl;
    dst.start();
    dst.join();
    return 0;
}
Re[7]: Многопоточность в современных плюсиках
От: Maniacal Россия  
Дата: 07.02.23 06:29
Оценка:
Здравствуйте, пффф, Вы писали:

П>Ну вот и путают. Классический мьютекс — это средство межпроцессного взаимодействия


Нет. Только именованные. В Линухах именованные только семафоры бывают, ЕМНИП. В Винде всё можно именовать. А семофоры вообще в std появились с c++20

Ещё норм вещь std::condition_variable, в линухах искаропки есть в стандарте POSIX, SysV или BSD, не помню уже.
Отредактировано 07.02.2023 6:35 Maniacal . Предыдущая версия . Еще …
Отредактировано 07.02.2023 6:31 Maniacal . Предыдущая версия .
Re[8]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 07.02.23 07:03
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Ещё норм вещь std::condition_variable, в линухах искаропки есть в стандарте POSIX, SysV или BSD, не помню уже.

https://learn.microsoft.com/en-us/windows/win32/sync/condition-variables
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[9]: Многопоточность в современных плюсиках
От: Maniacal Россия  
Дата: 07.02.23 07:22
Оценка: :)
Здравствуйте, CreatorCray, Вы писали:

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


M>>Ещё норм вещь std::condition_variable, в линухах искаропки есть в стандарте POSIX, SysV или BSD, не помню уже.

CC>https://learn.microsoft.com/en-us/windows/win32/sync/condition-variables

Это WinAPI, майкрософтовская реализаци со своим блекджеком и девушками с пониженной социальной ответственностью, я про стандарты.
Re[2]: Многопоточность в современных плюсиках
От: sergii.p  
Дата: 07.02.23 10:59
Оценка:
Здравствуйте, пффф, Вы писали:

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


П>Правильно ли я понимаю, что std::lock_guard и std::scoped_lock — аналогичны, но второй может лочить пачки разнородных объектов, а первый — только один mutex_type мьютекс?


да, lock_guard — частный случай scoped_lock. Также его можно считать deprecated с C++17
Re[2]: Многопоточность в современных плюсиках
От: B0FEE664  
Дата: 07.02.23 12:59
Оценка:
Здравствуйте, пффф, Вы писали:

П>А что-то типа виндового Event с авторесетом есть?

здесь
Автор: B0FEE664
Дата: 29.09.14
И каждый день — без права на ошибку...
Re: Многопоточность в современных плюсиках
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.02.23 20:32
Оценка:
Здравствуйте, пффф, Вы писали:

П>Появились вопросы. В винде я обычно использовал 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. А я не хочу парится об этом, и помнить, какая функция у меня лочит, а какая — нет.


std::recursive_mutex?

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


Вот прям аналога Event ты вряд ли найдешь. Посмотри на conditional variable. Вот тебе прям статья на Хабре:

https://habr.com/ru/post/182626/

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


Нестатическая функция: это не один указатель, а два: на this и на функцию. Поэтому и нужен переходник.

П>ЗЗЫ Может, часть из того что нужно можно на атомиках сделать? Или это плохая идея?


Плохая, если не умеешь. А если умеешь, не задаешь вопросы.
Re[3]: Многопоточность в современных плюсиках
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.02.23 20:34
Оценка:
Здравствуйте, пффф, Вы писали:

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


Оно в зависимости от реализации может быть легкое и не очень. Стандарт — он же описывает интерфейсы, а не как они реализованы. А как реализованы, очень зависит от платформы.

В целом, от нормальной реализации на "взрослой" платформе я бы ожидал, что то, что в принципе может быть сделано легким, будет сделано легким.
Re[2]: Многопоточность в современных плюсиках
От: пффф  
Дата: 07.02.23 20:35
Оценка: 1 (1)
Здравствуйте, Pzz, Вы писали:

Pzz>Вот прям аналога Event ты вряд ли найдешь. Посмотри на conditional variable. Вот тебе прям статья на Хабре:


Pzz>https://habr.com/ru/post/182626/


Видел. Статья — говно


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


Pzz>Нестатическая функция: это не один указатель, а два: на this и на функцию. Поэтому и нужен переходник.


Спасибо, КЭП


ЗЫ Ты ж не плюсовик вроде совсем, что тогда советы по плюсам даёшь?
Re[3]: Многопоточность в современных плюсиках
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.02.23 20:39
Оценка:
Здравствуйте, пффф, Вы писали:

П>ЗЫ Ты ж не плюсовик вроде совсем, что тогда советы по плюсам даёшь?


Плюсовик-не плюсовик, а про рекурсивный мьютекс сам знаю, а не на форуме спрашиваю.

C++-ная многопоточка очень напоминает по сути своей POSIX threads, оформленные в плюсовом стиле. А про POSIX threads мне доводилось кое-чего слышать...
Re: Многопоточность в современных плюсиках
От: пффф  
Дата: 07.02.23 20:40
Оценка:
Здравствуйте, пффф, Вы писали:

Всем спасибо за советы, запилил, нормальненько работает.

Отдельно — в закромах нашлась книжка: Энтони Уильямс, "C++. Практика многопоточного программирования". Полистал её немного, несколько помогло подразобраться. Особо рекламировать не буду, но вроде толковая, мне помогла. Надо будет почитать повнимательнее
Re[4]: Многопоточность в современных плюсиках
От: пффф  
Дата: 07.02.23 20:46
Оценка:
Здравствуйте, Pzz, Вы писали:

П>>ЗЫ Ты ж не плюсовик вроде совсем, что тогда советы по плюсам даёшь?


Pzz>Плюсовик-не плюсовик, а про рекурсивный мьютекс сам знаю, а не на форуме спрашиваю.


А я под виндой использовал CriticalSection, а под линупсом — сам аналог её писал, и мне как-то пофигу было, какие где мьютексы, где рекурсивные, а где — не очень


Pzz>C++-ная многопоточка очень напоминает по сути своей POSIX threads, оформленные в плюсовом стиле. А про POSIX threads мне доводилось кое-чего слышать...


Дьявол — он в деталях
Re[5]: Многопоточность в современных плюсиках
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.02.23 20:49
Оценка: -1
Здравствуйте, пффф, Вы писали:

Pzz>>Плюсовик-не плюсовик, а про рекурсивный мьютекс сам знаю, а не на форуме спрашиваю.


П>А я под виндой использовал CriticalSection, а под линупсом — сам аналог её писал, и мне как-то пофигу было, какие где мьютексы, где рекурсивные, а где — не очень


Ну молодец. А знал бы, как это правильно называется, воспользовался бы готовым.

В венде оно, кстати, не CriticalSection называется, а CRITICAL_SECTION. Шоб вырвиглаз наверняка.

Pzz>>C++-ная многопоточка очень напоминает по сути своей POSIX threads, оформленные в плюсовом стиле. А про POSIX threads мне доводилось кое-чего слышать...


П>Дьявол — он в деталях


Ну, я с бесами не общаюсь, тебе виднее.
Re[6]: Многопоточность в современных плюсиках
От: пффф  
Дата: 07.02.23 20:54
Оценка: 1 (1) -1
Здравствуйте, Pzz, Вы писали:

П>>А я под виндой использовал CriticalSection, а под линупсом — сам аналог её писал, и мне как-то пофигу было, какие где мьютексы, где рекурсивные, а где — не очень


Pzz>Ну молодец. А знал бы, как это правильно называется, воспользовался бы готовым.


А готового spin lock'а у вас там не было, потому и писал своё


Pzz>В венде оно, кстати, не CriticalSection называется, а CRITICAL_SECTION. Шоб вырвиглаз наверняка.


Спасибо, я в курсе. Не хотел наносить глазную травму


Pzz>>>C++-ная многопоточка очень напоминает по сути своей POSIX threads, оформленные в плюсовом стиле. А про POSIX threads мне доводилось кое-чего слышать...


П>>Дьявол — он в деталях


Pzz>Ну, я с бесами не общаюсь, тебе виднее.


С деталями — тоже?
Re[4]: Многопоточность в современных плюсиках
От: Константин Черногория  
Дата: 07.02.23 21:39
Оценка:
Здравствуйте, vopl, Вы писали:

V>std::mutex обычно реализован через winapi-CriticalSection

Мне кажется последние годы обычно через slim reader/writer lock
Re[7]: Многопоточность в современных плюсиках
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.02.23 22:26
Оценка: :)
Здравствуйте, пффф, Вы писали:

Pzz>>Ну молодец. А знал бы, как это правильно называется, воспользовался бы готовым.


П>А готового spin lock'а у вас там не было, потому и писал своё


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

В user space толку от него заметно меньше. Если его кто-то держит, кому в данный момент процессора не хватило, а кто-то другой его хочет, так и будет крутиться, как угорелый, пока текущему владельцу опять не дадут поработать.

Да, я в курсе, что Microsoft считает, что при входе в критическую секцию есть смысл немного поболтаться на спинлоке в надежде, что вдруг повезет.
Re[8]: Многопоточность в современных плюсиках
От: пффф  
Дата: 07.02.23 22:42
Оценка: 1 (1) +1 -1
Здравствуйте, Pzz, Вы писали:

Pzz>>>Ну молодец. А знал бы, как это правильно называется, воспользовался бы готовым.


П>>А готового spin lock'а у вас там не было, потому и писал своё


Pzz>Spin lock хорош в ядре, где его захват попутно блокирует скедулер, и, тем самым, обеспечивает синхронизацию между ядрами процессора.


Это не отменяет того факта, что спин лока в линупсе долго не было


Pzz>В user space толку от него заметно меньше. Если его кто-то держит, кому в данный момент процессора не хватило, а кто-то другой его хочет, так и будет крутиться, как угорелый, пока текущему владельцу опять не дадут поработать.


Есть статистика? Или так, чисто побалаболить?

Спинлок здорового человека засыпает на мьютексе после некоторого количества циклов. Как угорелый крутится только спин лок курильщика, и, возможно, линупсоида


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


Если потрогать пару переменных — то несомненно, это дешевле, чем сразу в ядро нырять. А если что-то долгое — так у винды можно wait'ить почти на любом хэндле, и тут опять мьютексы не нужны. Это просто POSIX ущербный
Re[10]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 07.02.23 23:38
Оценка: 1 (1) +1 -1
Здравствуйте, Maniacal, Вы писали:

M>я про стандарты.

Posix это не стандарт а говно мамонта.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re: Многопоточность в современных плюсиках
От: LaptevVV Россия  
Дата: 08.02.23 04:59
Оценка:
Вот этого товарища послущай
https://www.youtube.com/watch?v=NawpxG81RRk
Всего видюх по 10-20 минут — самое оно для начала параллельности в С++
Все очень просто и понятно.
И про mutex, и про lock_guard, и про unique_guard, про recursive_mutex
И про передачу параметров с возвратом результатов, и про вызов методов.
В общем — абсолютно необходимый минимум.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[7]: Многопоточность в современных плюсиках
От: Zhendos  
Дата: 08.02.23 08:58
Оценка:
Здравствуйте, пффф, Вы писали:

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


П>>>А я под виндой использовал CriticalSection, а под линупсом — сам аналог её писал, и мне как-то пофигу было, какие где мьютексы, где рекурсивные, а где — не очень


Pzz>>Ну молодец. А знал бы, как это правильно называется, воспользовался бы готовым.


П>А готового spin lock'а у вас там не было, потому и писал своё


А зачем?

В Linux mutex реализован через атомарные переменные,
то есть там несколько циклов происходит попытка "захватить" блокировку,
по сути "spin lock", а только потом поток засыпает.
По идее там все выверено по количеству итераций "spin lock" перед засыпанием,
чтобы зря циклы CPU не жечь в "busy loop" и не делать лишних системных вызовов
если lock/unlock защищают небольшой участок кода.
Re[8]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 08.02.23 17:46
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>В Linux mutex реализован через атомарные переменные,

Z>то есть там несколько циклов происходит попытка "захватить" блокировку,
Z>по сути "spin lock", а только потом поток засыпает.
Ты токашо описал виндовый Critical Section.

Z>По идее там все выверено по количеству итераций "spin lock" перед засыпанием,

И оно само угадывает какой длительности код под локом чтоб проспинать ровно сколько нужно, ага!
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[11]: Многопоточность в современных плюсиках
От: Maniacal Россия  
Дата: 09.02.23 10:07
Оценка:
Здравствуйте, CreatorCray, Вы писали:

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


M>>я про стандарты.

CC>Posix это не стандарт а говно мамонта.

POSIX (англ. Portable Operating System Interface — переносимый интерфейс операционных систем) — набор стандартов, описывающих интерфейсы между операционной системой и прикладной программой (системный API), библиотеку языка C и набор приложений и их интерфейсов. Стандарт создан для обеспечения совместимости различных UNIX-подобных операционных систем и переносимости прикладных программ на уровне исходного кода, но может быть использован и для не-Unix систем.

Серия стандартов POSIX была разработана комитетом 1003 IEEE. Международная организация по стандартизации (ISO) совместно c Международной электротехнической комиссией (IEC) приняла стандарт POSIX под названием ISO/IEC 9945[2]. Версии стандарта POSIX являются основой соответствующих версий стандарта Single UNIX Specification. Стандарт POSIX определяет интерфейс операционной системы, а соответствие стандарту Single UNIX Specification определяет реализацию интерфейса и позволяет операционным системам использовать торговую марку UNIX[3].


Т.е. SysV и BSD тоже не стандарты? Зачем же они тогда в линуксах поддержаны. Да, мелкомягкие их ещё 20 лет назад не признали, свой блэкджек замутили.
Re[12]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 09.02.23 21:24
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Зачем же они тогда в линуксах поддержаны.

Это ты у пингвина спрашивай

M> Да, мелкомягкие их ещё 20 лет назад не признали, свой блэкджек замутили.

И правильно сделали, куда вменяемее получилось.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[13]: Многопоточность в современных плюсиках
От: σ  
Дата: 09.02.23 22:49
Оценка:
M>> Да, мелкомягкие их ещё 20 лет назад не признали, свой блэкджек замутили.
CC>И правильно сделали, куда вменяемее получилось.
Но потом всё равно пришлось притаскивать к себе UTF-8, ANSI escape sequences, симлинки и прочие достижения цивилизованного мира. Куда деваться с подводной лодки?
Хотя, наверное, asynchronous IO в NT более лучше сделан, чем в Unix. Что, собственно, неудивительно, учитывая разницу во времени между их появлением.
Отредактировано 09.02.2023 22:50 σ . Предыдущая версия .
Re[14]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 09.02.23 23:30
Оценка:
Здравствуйте, ?, Вы писали:

CC>>И правильно сделали, куда вменяемее получилось.

?>Но потом всё равно пришлось притаскивать к себе UTF-8
Это в каком месте то? Везде со времён NT используется UCS2

?> ANSI escape sequences
Опять таки где?

?> симлинки
Банально расширили Reparse points

?> и прочие достижения цивилизованного мира.
А именно?

?>Что, собственно, неудивительно, учитывая разницу во времени между их появлением.
В основном потому что им не надо было запихивать себя в прокрустово ложе откровенно устаревших интерфейсов.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[13]: Многопоточность в современных плюсиках
От: Maniacal Россия  
Дата: 10.02.23 07:24
Оценка:
Здравствуйте, CreatorCray, Вы писали:

M>> Да, мелкомягкие их ещё 20 лет назад не признали, свой блэкджек замутили.

CC>И правильно сделали, куда вменяемее получилось.

Согласен, но когда под Линух пишешь или кросс-платформенное решение, то никак не помогает. Если только собственные библиотеки (или чужие) юзать, которые в зависимости от платформы компилируют одну свою часть реализации или другую.
у Винды очень тесная интеграция GUI и API те же messages. В *nix универсальный и, потому, более тормозной GUI.
Re[14]: Многопоточность в современных плюсиках
От: CreatorCray  
Дата: 11.02.23 00:34
Оценка: +1
Здравствуйте, Maniacal, Вы писали:

M>Согласен, но когда под Линух пишешь или кросс-платформенное решение, то никак не помогает.

И не должно.

M>В *nix универсальный и, потому, более тормозной GUI.

Всё универсальное это мешок компромиссов, в итоге работает одинаково хреново на всём.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re: Многопоточность в современных плюсиках
От: serg_joker Украина  
Дата: 04.03.23 21:57
Оценка: :)
Здравствуйте, пффф, Вы писали:

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

Полистал ответы, не увидел вариантов без "переходника". Может, пропустил.
Переходник не нужен. Вот:
struct A
{
    void run(int, const std::string&) { /*do stuff*/ }
};

int main()
{
    A a;
    std::thread t{&A::run, &a, 1, ""};
    t.join();
}
Re: Многопоточность в современных плюсиках
От: gyraboo  
Дата: 05.03.23 06:43
Оценка:
Здравствуйте, пффф, Вы писали:

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


В джаве сейчас моднявая тема — реактивность. Она предлагает отказаться от потоков в пользу неблокирующего кода, работающего на ограниченном количестве потоков (т.н. рельсах). Профит в том, что переключение контекста потоков очень дорогое, а тут переключения нет, поэтому нагрузку держит бОльшую. Но писать код реактивных стримов надо так, чтобы он был неблокирующим, иначе он залочит рельсу и застопорит конвейер рельсы.
В плюсах есть нечто подобное?
Отредактировано 05.03.2023 7:42 gyraboo . Предыдущая версия .
Re[2]: Многопоточность в современных плюсиках
От: rudzuk  
Дата: 05.03.23 09:47
Оценка: +1
Здравствуйте, gyraboo, Вы писали:

g> В джаве сейчас моднявая тема — реактивность. Она предлагает отказаться от потоков в пользу неблокирующего кода, работающего на ограниченном количестве потоков (т.н. рельсах). Профит в том, что переключение контекста потоков очень дорогое, а тут переключения нет, поэтому нагрузку держит бОльшую. Но писать код реактивных стримов надо так, чтобы он был неблокирующим, иначе он залочит рельсу и застопорит конвейер рельсы.


Типа, кооперативную многозадачность переизобрели что-ли?
avalon/3.0.2
Re[2]: Многопоточность в современных плюсиках
От: Zhendos  
Дата: 05.03.23 12:01
Оценка:
Здравствуйте, gyraboo, Вы писали:

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


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


G>В джаве сейчас моднявая тема — реактивность. Она предлагает отказаться от потоков в пользу неблокирующего кода, работающего на ограниченном количестве потоков (т.н. рельсах). Профит в том, что переключение контекста потоков очень дорогое, а тут переключения нет, поэтому нагрузку держит бОльшую. Но писать код реактивных стримов надо так, чтобы он был неблокирующим, иначе он залочит рельсу и застопорит конвейер рельсы.

G>В плюсах есть нечто подобное?

С каких пор реактивность модная? Вроде уже много
кто стал отказываться из-за "calback hell" в пользу
"async". И в C++ эта фича есть в C++20: https://en.cppreference.com/w/cpp/language/coroutines
Отредактировано 06.03.2023 6:29 Zhendos . Предыдущая версия .
Re[2]: Многопоточность в современных плюсиках
От: kov_serg Россия  
Дата: 05.03.23 12:10
Оценка:
Здравствуйте, gyraboo, Вы писали:

G>В джаве сейчас моднявая тема — реактивность. Она предлагает отказаться от потоков в пользу неблокирующего кода, работающего на ограниченном количестве потоков (т.н. рельсах). Профит в том, что переключение контекста потоков очень дорогое, а тут переключения нет, поэтому нагрузку держит бОльшую. Но писать код реактивных стримов надо так, чтобы он был неблокирующим, иначе он залочит рельсу и застопорит конвейер рельсы.

G>В плюсах есть нечто подобное?

Так можно было и на обычном C писать (с некоторыми оговорками):
  track-fn.h
/* track-fn.h */
#pragma once

enum TrackConsts { track_no_limit=-1, track_start_line=0, track_end_line=-1 };
enum TrackResultCodes { track_rc_done=0, track_rc_active=1, track_rc_int=2 };

typedef struct Track { int line,limit; } Track;

#define TRACK_RESET(v) { Track *_track=(v); _track->line=0; _track->limit=1; }
#define TRACK_SET_LIMIT(track,n) { (track)->limit=n; }

#define TRACK_BEGIN(v) { Track *_track=(v); track_begin: \
    switch(_track->line) { default: case 0: TRACK_POINT
#define TRACK_POINT { case __LINE__: _track->line=__LINE__; \
    if (_track->limit>=0 && !_track->limit--) { _track->limit=1; return 1; } }
#define TRACK_END   track_end: case -1: _track->line=-1; return 0; } \
    track_interrupt: return 2; }

#define TRACK_END_R track_end: _track->line=-1; _track->limit=1; return 0; } \
    track_interrupt: return 2; }

#define TRACK_REPEAT_LAST goto track_begin;
#define TRACK_LEAVE       goto track_end;
#define TRACK_INTERRUPT   goto track_interrupt;

#define TRACK_CALL(fn,state) { int rc; \
    for(fn##_reset(state);0!=(rc=fn(state));) { \
        if (rc==track_rc_int) { TRACK_INTERRUPT } else { TRACK_POINT } \
    }}
/* tracks.c */
#include <stdio.h>
#include "track-fn.h"

typedef struct {
    Track track[1];
    int in0;
} fn1_state;
void fn1_reset(fn1_state *self) { TRACK_RESET(self->track); }

int fn1(fn1_state *self) {
    TRACK_BEGIN(self->track)
        printf("\tfn1.1\t%d\n",self->in0);
        TRACK_POINT
        printf("\tfn1.2\t%d\n",self->in0);
    TRACK_END
}

typedef struct {
    Track track[1];
    fn1_state fn1[1]; 
    int i;
} fn2_state;
void fn2_reset(fn2_state *self) { TRACK_RESET(self->track); }

int fn2(fn2_state *self) {
    TRACK_BEGIN(self->track)
        printf("fn2.1\n");
        TRACK_POINT
        for(self->i=1;self->i<=3;self->i++) {
            self->fn1->in0=self->i; /* function input arg */
            TRACK_CALL(fn1,self->fn1)
        }
        TRACK_POINT 
        printf("fn2.2\n");
    TRACK_END
}

int main(int argc, char const *argv[]) {    
    fn2_state s[1];
    fn2_reset(s);

    s->track->limit=3; fn2(s);
    printf("--\n");
    s->track->limit=track_no_limit; fn2(s);
    return 0;
}

А в плюсах только C++20 добавили коротины, но слегка через жопу как обычно.
  cpp20.cpp
// g++-10 -std=c++20 -fcoroutines cpp20.cpp && ./a.out
#include <coroutine>
#include <iostream>

struct resumable {
    struct promise_type {
        using coro_handle = std::coroutine_handle<promise_type>;
        auto get_return_object() { return coro_handle::from_promise(*this); }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };
    using coro_handle = std::coroutine_handle<promise_type>;
    resumable(coro_handle handle) : handle(handle) {}
    bool resume() { if (!handle.done()) handle.resume(); return !handle.done(); }
    ~resumable() { if (handle) handle.destroy(); }
private:
    coro_handle handle;
};

resumable fn1() {
    std::cout<<"Hello"<<std::endl;
    co_await std::suspend_always{};
    std::cout<<"World"<<std::endl;
    co_await std::suspend_always{};
    std::cout<<"!!!"<<std::endl;
}

int main(int argc, char const *argv[]) {
    auto t=fn1();
    t.resume();
    t.resume();
    t.resume();
    return 0;
}
Re[3]: Многопоточность в современных плюсиках
От: gyraboo  
Дата: 05.03.23 16:59
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>С каких пор реактивность модная? Вроде уже много

Z>кто стал отказываться из-зак "calback hell" в пользу
Z>"async".

И что же, всё богатство конвейерных операторов реактивных потоков тоже в топку?
Re[4]: Многопоточность в современных плюсиках
От: Zhendos  
Дата: 06.03.23 06:31
Оценка:
Здравствуйте, gyraboo, Вы писали:

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


Z>>С каких пор реактивность модная? Вроде уже много

Z>>кто стал отказываться из-зак "calback hell" в пользу
Z>>"async".

G>И что же, всё богатство конвейерных операторов реактивных потоков тоже в топку?


А зачем все это богатство нужно если можно просто написать несколько библиотечных "async" функций
или просто "if/while"?
Re[5]: Многопоточность в современных плюсиках
От: gyraboo  
Дата: 06.03.23 07:10
Оценка:
Здравствуйте, Zhendos, Вы писали:

G>>И что же, всё богатство конвейерных операторов реактивных потоков тоже в топку?


Z>А зачем все это богатство нужно если можно просто написать несколько библиотечных "async" функций

Z>или просто "if/while"?

Ты мне глаза открыл. Можно либо написать самому, если оно реюзается, оформить в виде библиотеки, тем более что код async — он нагляднее. Спасибо.
Либо вообще под вопросом их использование, раньше без них как-то жили, и ничего.
Re[8]: Многопоточность в современных плюсиках
От: ononim  
Дата: 06.03.23 10:35
Оценка: +2
П>>Ну вот и путают. Классический мьютекс — это средство межпроцессного взаимодействия
M>Нет. Только именованные.
Че ето вдруг. DuplicateHandle или отнаследованные хэндлы мутексов так же прекрасно работают между разными процессами.
НО проблема тут не в С++, а в том что изначальная* структура ядра винды была спроектированна умными людьми — с ортогональной системой типов объектов ядра, а юникс делался по принципу 'ну че пишем очередную версию червяка Морриса и нам нужны средства межпроцессной синхронизации, ну давайте запилим sem_open'

* Теперь то конечно уже и винда г..но — то есть плоды противоестественной любви микрософта и линукса в недавнем прошлом...
Как много веселых ребят, и все делают велосипед...
Отредактировано 06.03.2023 10:36 ononim . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.