Исходник ktcoro_wait - задержки без потоков

kin4stat

mq-team
Автор темы
Всефорумный модератор
2,731
4,693

ktcoro_wait​

Приостановка выполенения функции на время основанное на корутинах C++20

Примеры кода​

C++:
#include <iostream>
#include <chrono>

#include "ktcoro_wait.hpp"

ktwait bar() {
    using namespace std::chrono_literals;
    while (true) {
        std::cout << "Я печатаю каждые 2.5 секунды" << std::endl;
        co_await 2.5s;
    }
}

ktwait baz() {
    using namespace std::chrono_literals;
    co_await 3s;
    std::cout << "Привет от baz спустя 3 секунды" << std::endl;
}

ktwait foo(int time) {
    while (true) {
        co_await std::chrono::seconds(time);
        std::cout << "Я вызываю baz каждые " << time << " секунд" << std::endl;
        co_await baz();
        std::cout << "А еще жду пока baz выполнится" << std::endl;
    }
}

int main() {
    ktcoro_tasklist tasklist;
    tasklist.add_task(foo, 2);
    tasklist.add_task(bar);
    while (true) {
        tasklist.process();
    }
}

Download & Source:
 
Последнее редактирование:

memir

🇷🇺
Всефорумный модератор
332
594
.
photo_2021-10-14_07-13-32.jpg
 

SR_team

like pancake
BH Team
4,707
6,347
remove_if же не удаляет элементы по настоящему, только меняет итераторы



UPD: Я еблан, там и не надо ничего удалять. @kin4stat как оно будет работать на нескольких потоках?


UPD2: Проверил сам потоки. Все корутины катчатся в инстанс потока main. И bar, который вызывает co_wait из потока t1, продолжает свое выполнение уже в потоке main
C++:
#include <iostream>
#include <chrono>
#include <thread>

#include "include/ktcoro_wait.hpp"

ktwait bar() {
    using namespace std::chrono_literals;
    while (true) {
        std::cout << "I am called every 2.5 seconds" << std::endl;
        co_await 2.5s;
    }
}

ktwait baz() {
    using namespace std::chrono_literals;
    co_await 3s;
    std::cout << "hello from baz after 3 seconds" << std::endl;
}

ktwait foo(int time) {
    while (true) {
        co_await std::chrono::seconds(time);
        std::cout << "I am calling baz every " << time << " seconds" << std::endl;
        co_await baz();
        std::cout << "I am not waiting for baz" << std::endl;
    }
}

void thread(std::stop_token stoken){
    bar();
    while (!stoken.stop_requested()){
        std::this_thread::yield();
    }
}

int main() {
    using namespace std::chrono_literals;
   
    foo(2);
    std::jthread t1(thread);
    for (int i = 0; i < 1000; ++i) {
        ktcoro_wait::Instance().process();
        std::this_thread::sleep_for(10ms);
    }
    t1.request_stop();
    if (t1.joinable()){
        t1.join();
    }
}
 
Последнее редактирование:

kin4stat

mq-team
Автор темы
Всефорумный модератор
2,731
4,693
UPD2: Проверил сам потоки. Все корутины катчатся в инстанс потока main. И bar, который вызывает co_wait из потока t1, продолжает свое выполнение уже в потоке main
Починил. Теперь можно гонять таски своего потока, чужого потока, и все таски в приципе.
Также теперь при эвейте другой таски текущая будет ждать окончания выполнения таски которую co_await'нули.
Также теперь можно удалять таски для чужих потоков, и в приципе во всем тасклисте по всем потокам. Небезопасно если вы удаляете таску которая эвейтнула другую таску. Мне слишком лень это фиксить.
 

SR_team

like pancake
BH Team
4,707
6,347
Починил. Теперь можно гонять таски своего потока, чужого потока, и все таски в приципе.
Также теперь при эвейте другой таски текущая будет ждать окончания выполнения таски которую co_await'нули.
Также теперь можно удалять таски для чужих потоков, и в приципе во всем тасклисте по всем потокам. Небезопасно если вы удаляете таску которая эвейтнула другую таску. Мне слишком лень это фиксить.
а нельзя несколько инстансов завести? Просто в текущей реализации пока выполняются корутины из одного потока, корутины другого потока спят, а до вызова co_wait может быть очень тяжелая операция
 
  • Нравится
Реакции: etereon

kin4stat

mq-team
Автор темы
Всефорумный модератор
2,731
4,693
UPDATE:
Добавлено создание пользовательских инстансов тасклистов.
Также теперь можно безопасно удалять таски из очереди
 
  • Нравится
Реакции: PanSeek

Ya Zaregalsya

Известный
370
131
add_task() будет работать с лямбда функциями?

Такая проблема, заголовочный файл обсыпан ошибками, мол std не содержит никаких корутинов. Что можно сделать в такой ситуации?
1635515075556.png

1635516105907.png


UPD: Исправил ошибку. Нужно было перейти на самый свежий стандарт языка.

Лямбды на месте 👍


C++:
tasklist.add_task(
    [](int first, bool second) -> ktwait {
        using namespace std::chrono_literals;
        SF->getSAMP()->getChat()->AddChatMessage(-1, "#1 First: %i; Second: %d;", first, second);
        co_await 5s;
        SF->getSAMP()->getChat()->AddChatMessage(-1, "#2 First: %i; Second: %d;", first, second);
    }, 3, true);
 
Последнее редактирование:

Ya Zaregalsya

Известный
370
131
Удобная либа. Лямбды делаются легко. Возник только такой вопрос, можно ли как-то уйти ото всех этих секунд и миллисекунд, и работать чисто по кол-ву вызовов process()? Например, продолжить выполнение через 10 циклов вызовов process(). Сделал два tasklist, один вызывается в потоке, другой в хуке на рендер, чтобы один вызывать по времени, а другой по кадрам. Но если передавать в co_await обычное число, то размер этого числа ни на что не влияет:


C++:
#pragma once
#include "SAMPFUNCS_API.h"
#include "game_api.h"

#include <chrono>
#include "ktcoro_wait.hpp"

extern SAMPFUNCS* SF;
extern ktcoro_tasklist threadTask;
extern ktcoro_tasklist presentTask;

namespace examples
{
    void testktcoro()
    {
        SF->getSAMP()->registerChatCommand("testktcoro", [](std::string param)->void
        {
                threadTask.add_task([]()->ktwait
                {
                    while (true)
                    {
                        SF->getSAMP()->getChat()->AddChatMessage(-1, "threadTask");
                        co_await 1;
                    }
                });
                presentTask.add_task([]()->ktwait
                {
                    while (true)
                    {
                        SF->getSAMP()->getChat()->AddChatMessage(-1, "presentTask");
                        co_await 1;
                    }
                });
        });
    }
}

Компилятор жалуется на либу за повторное включение, несмотря на #pragma once во всех файлах проекта. Конкретно на функции remove_task и remove_task_recursively.
 
Последнее редактирование:

kin4stat

mq-team
Автор темы
Всефорумный модератор
2,731
4,693
Например, продолжить выполнение через 10 циклов вызовов process()
хз зачем это может понадобиться, но как костыль:

C++:
for (auto i = 0u; i < 10u; i++) {
    co_yield;
}

Да-да умею отвечать вовремя

Компилятор жалуется на либу за повторное включение, несмотря на #pragma once во всех файлах проекта. Конкретно на функции remove_task и remove_task_recursively.
Попробуй вот эти две функции отметить как inline
1637077189320.png
 
  • Нравится
Реакции: Ya Zaregalsya

Ya Zaregalsya

Известный
370
131
хз зачем это может понадобиться, но как костыль:

C++:
for (auto i = 0u; i < 10u; i++) {
    co_yield;
}

Да-да умею отвечать вовремя


Попробуй вот эти две функции отметить как inline
Посмотреть вложение 122581
Если память не подводит, то inline пробовал, но не сработало. Пришлось перенести эти функции в отдельный .cpp файл, а в .hpp оставить только объявление.
 

kin4stat

mq-team
Автор темы
Всефорумный модератор
2,731
4,693
Если память не подводит, то inline пробовал, но не сработало. Пришлось перенести эти функции в отдельный .cpp файл, а в .hpp оставить только объявление.
Попробуй обновить файлы с гитхаба