A golang-style C++ coroutine library and more.

Basic (中文)

CO is an elegant and efficient C++ base library that supports Linux, Windows and Mac platforms. It pursues minimalism and efficiency, and does not rely on third-party library such as boost.

CO includes coroutine library (golang-style), network library (tcp/http/rpc), log library, command line and configuration file parsing library, unit testing framework, json library and other basic components.

Documents

Highlights

  • co

    co is a golang-style C++ coroutine library with the following features:

    • Support multi-thread scheduling, the default number of threads is the number of system CPU cores.

    • Coroutines share the thread stack (the default size is 1MB), and the memory footprint is extremely low, a single machine can easily create millions of coroutines.

    • Support system api hook (Linux & Mac).

    • Support coroutine lock co::Mutex.

    • Support coroutine synchronization event co::Event.

    • Support coroutine pool co::Pool.

    • create coroutine with go():

    void fun() {
        std::cout << "hello world" << std::endl;
    }
    
    go(fun);
  • so

    so is a C++ network library based on coroutines. You can easily write network programs that support both ipv4 and ipv6 with this library. It includes the following modules:

    • tcp module, supports general tcp programming.

    • http module, supports basic http programming.

    • rpc module, implements a rpc framework based on json, single-threaded qps can reach 120k+.

    • Write a static web server:

    #include "co/flag.h"
    #include "co/log.h"
    #include "co/so.h"
    
    DEF_string(d, ".", "root dir"); // Specify the root directory of the web server
    
    int main(int argc, char** argv) {
        flag::init(argc, argv);
        log::init();
    
        so::easy(FLG_d.c_str()); // mum never have to worry again
    
        return 0;
    }
    • Write a general http server
    http::Server serv("0.0.0.0", 80);
    
    serv.on_req(
        [](const http::Req& req, http::Res& res) {
            if (req.is_method_get()) {
                if (req.url() == "/hello") {
                    res.set_status(200);
                    res.set_body("hello world");
                } else {
                    res.set_status(404);
                }
            } else {
                res.set_status(501);
            }
        }
    );
    
    serv.start();
  • log

    log is a super fast local logging system, printing logs is safer than printf:

    LOG << "hello "<< 23;   // info
    ELOG << "hello again";  // error

    Let's see how fast it is below:

    log vs glog google glog co/log
    win2012 HHD 1.6MB/s 180MB/s
    win10 SSD 3.7MB/s 560MB/s
    mac SSD 17MB/s 450MB/s
    linux SSD 54MB/s 1023MB/s

    The above table is the test result of one million info logs (about 50 bytes each) continuously printed by a single thread. The co/log is almost two orders of magnitude faster than glog.

    Why is it so fast? The first is that it is based on fastream that is 8-25 times faster than sprintf. The second is that it has almost no memory allocation operations.

  • flag

    flag is a command line and configuration file parsing library that supports automatic generation of configuration files.

    #include "co/flag.h"
    
    DEF_int32(i, 32, "comments");
    DEF_string(s, "xxx", "string type");
    
    int main(int argc, char** argv) {
        flag::init(argc, argv);
        std::cout << "i: "<< FLG_i << std::endl;
        std::cout << "s: "<< FLG_s << std::endl;
        return 0;
    }

    Build and run:

    ./xx                         # start with default parameters
    ./xx -i=4k -s="hello world"  # integers can take unit k,m,g,t,p (case insensitive)
    ./xx -i 4k -s "hello world"  # equivalent to above
    ./xx --mkconf                # automatically generate configuration file xx.conf
    ./xx -config=xx.conf         # start from configuration file
  • json

    json is a json library comparable to rapidjson, if you use jemalloc, the performance of parse and stringify will be further improved. This library's support for the json standard is not as comprehensive as rapidjson, but it can meet the basic needs of programmers and is easier to use.

Components

  • co/include
    Header files of libco.

  • co/src
    Source files of libco.

  • co/test
    Some test code, each .cc file will be compiled into a separate test program.

  • co/unitest
    Some unit test code, each .cc file corresponds to a different test unit, and all code is compiled into a single test program.

  • co/gen
    A code generation tool automatically generates rpc framework code according to the proto file.

Compiling

xmake

Xmake is recommended for compiling the CO project.

  • Compiler

  • Install xmake

    For windows, mac and debian/ubuntu, you can directly go to the xmake release page to download the installation package. For other systems, please refer to xmake's installation instructions.

    Xmake disables compilation as root by default on linux. ruki says it is not safe. You can add the following line to ~/.bashrc to enable root compilation:

    export XMAKE_ROOT=y
  • Quick start

    # All commands are executed in the root directory of co (the same below)
    xmake       # build libco and gen by default
    xmake -a    # build all projects (libco, gen, co/test, co/unitest)
  • Build libco

    xmake build libco      # build libco only
    xmake -b libco         # the same as above
  • Build and run unitest code

    co/unitest is unit test code that verifies the correctness of the functionality of the base library.

    xmake build unitest    # build can be abbreviated as -b
    xmake run unitest -a   # run all unit tests
    xmake r unitest -a     # the same as above
    xmake r unitest -os    # run unit test os
    xmake r unitest -json  # run unit test json
  • Build and run test code

    co/test contains some test code. You can easily add a xxx.cc source file in the co/test directory, and then execute xmake build xxx to build it.

    xmake build flag             # flag.cc
    xmake build log              # log.cc
    xmake build json             # json.cc
    xmake build rapidjson        # rapidjson.cc
    xmake build rpc              # rpc.cc
    xmake build easy             # so/easy.cc
    xmake build pingpong         # so/pingpong.cc
    
    xmake r flag -xz             # test flag
    xmake r log                  # test log
    xmake r log -cout            # also log to terminal
    xmake r log -perf            # performance test
    xmake r json                 # test json
    xmake r rapidjson            # test rapidjson
    xmake r rpc                  # start rpc server
    xmake r rpc -c               # start rpc client
    xmake r easy -d xxx          # start web server
    xmake r pingpong             # pingpong server:   127.0.0.1:9988
    xmake r pingpong ip=::       # pingpong server:   :::9988  (ipv6)
    xmake r pingpong -c ip=::1   # pingpong client -> ::1:9988
  • Build gen

    # It is recommended to put gen in the system directory (e.g. /usr/local/bin/).
    xmake build gen
    gen hello_world.proto

    Proto file format can refer to hello_world.proto.

  • Installation

    # Install header files, libco, gen by default.
    xmake install -o pkg         # package related files to the pkg directory
    xmake i -o pkg               # the same as above
    xmake install -o /usr/local  # install to the /usr/local directory

cmake

izhengfan has helped to provide cmake support:

  • Build libco and gen by default.
  • The library files are in the build/lib directory, and the executable files are in the build/bin directory.
  • You can use BUILD_ALL to compile all projects.
  • You can use CMAKE_INSTALL_PREFIX to specify the installation directory.
mkdir build && cd build
cmake ..
cmake .. -DBUILD_ALL=ON -DCMAKE_INSTALL_PREFIX=pkg
make -j8
make install

License

CO is licensed under the MIT License. It includes code from some other projects, which have their own licenses, see details in LICENSE.md.

Special thanks

  • The code of co/context is from tbox by ruki, special thanks!
  • The English reference documents of CO are translated by Leedehai (1-10), daidai21 (11-15) and google, special thanks!
  • ruki has helped to improve the xmake compilation scripts, thanks in particular!
  • izhengfan provided cmake compilation scripts, thank you very much!

Donate

Goto the Donate page.

Owner
Alvin
Keep simple.
Alvin
Comments
  • It's possible to coroutinize blocking sockets (?)

    It's possible to coroutinize blocking sockets (?)

    co_recv() is taken from co's doc and simplified for system sockets. It requires the socket to be set in non-blocking mode. co_recv_r() is basically co_recv() but with read/wait ordering switched. And it works on both blocking and non-blocking sockets?

    // doc's approach
    // https://idealvin.github.io/en/co/coroutine/#coroutineization
    int co_recv(int socket, void* buf, int n, int ms = 10000)
    {
        do
        {
            /* ============ READ FIRST ============ */
            if (const auto r = co::recv(socket, buf, n); r > 0)
                return r;
            else if (r == 0)
                return 0;
    
            /* ============ WAIT AFTER ============ */
            co::IoEvent ev(socket, co::ev_read);
            if (!ev.wait(ms))
                return -1;
        }
        while (true);
    }
    // Supports both blocking and non-blocking sockets, but are there pitfalls?
    int co_recv_r(int socket, void* buf, int n, int ms = 10000)
    {
        do
        {
            /* ============ WAIT FIRST ============ */
            co::IoEvent ev(socket, co::ev_read);
            if (!ev.wait(ms))
                return -1;
    
            /* ============ READ AFTER ============ */
            if (const auto r = co::recv(socket, buf, n); r > 0)
                return r;
            else if (r == 0)
                return 0;
        }
        while (true);
    }
    

    Full code for a simple test:

    #include "co/all.h"
    
    // doc's approach
    // https://idealvin.github.io/en/co/coroutine/#coroutineization
    int co_recv(int socket, void* buf, int n, int ms = 10000)
    {
        do
        {
            /* ============ READ FIRST ============ */
            if (const auto r = co::recv(socket, buf, n); r > 0)
                return r;
            else if (r == 0)
                return 0;
    
            /* ============ WAIT AFTER ============ */
            co::IoEvent ev(socket, co::ev_read);
            if (!ev.wait(ms))
                return -1;
        }
        while (true);
    }
    // Supports both blocking and non-blocking sockets, but are there pitfalls?
    int co_recv_r(int socket, void* buf, int n, int ms = 10000)
    {
        do
        {
            /* ============ WAIT FIRST ============ */
            co::IoEvent ev(socket, co::ev_read);
            if (!ev.wait(ms))
                return -1;
    
            /* ============ READ AFTER ============ */
            if (const auto r = co::recv(socket, buf, n); r > 0)
                return r;
            else if (r == 0)
                return 0;
        }
        while (true);
    }
    void handle1(tcp::Connection* conn)
    {
        std::cout << std::time(nullptr) << ' ' << __PRETTY_FUNCTION__ << " Start " << std::endl;
        uint8_t buffer[256]{};
        // while (const auto bytes = co_recv(conn->socket(), buffer, 256))
        while (const auto bytes = co_recv_r(conn->socket(), buffer, 256))
            conn->send(buffer, bytes);
        delete conn;
        std::cout << std::time(nullptr) << ' ' << __PRETTY_FUNCTION__ << " End " << std::endl;
    }
    void handle2(tcp::Connection*)
    {
        std::cout << std::time(nullptr) << ' ' << __PRETTY_FUNCTION__ << std::endl;
    }
    void on_connection(tcp::Connection* conn)
    {
        fcntl(conn->socket(), F_SETFL, fcntl(conn->socket(), F_GETFL) & ~O_NONBLOCK);
        if (fcntl(conn->socket(), F_GETFL) & O_NONBLOCK)
            throw std::runtime_error(std::string(__PRETTY_FUNCTION__) + ": the socket is still in non-blocking mode. ");
        auto* s = co::next_scheduler();
        s->go(handle1, conn);
        s->go(handle2, conn);
    }
    void client()
    {
        tcp::Client c("127.1", 8899);
        if (!c.connect(3000))
            throw std::runtime_error(std::string(__PRETTY_FUNCTION__) + ": failed to connect. ");
        for (int i = 0; i < 3; ++i)
        {
            c.send("hello", 5);
            char buffer[6]{};
            if (c.recv(buffer, 5))
            {
                //std::cout << __PRETTY_FUNCTION__ << ": " << buffer << std::endl;
            }
            sleep::sec(1);
        }
    }
    int main(int, char**)
    {
        tcp::Server serv;
        serv.on_connection(on_connection);
        serv.start("0.0.0.0", 8899);
    
        sleep::ms(200);
        go(client);
    
        while (true)
            sleep::sec(1024);
    }
    
    

    With co_recv_r() handle2() will be executed between handle1()'s beginning and ending, no matter whether the socket's blocking flag is set or not. But with co_recv() it only happens if the socket is set in non-blocking.

    I wonder if there is any pitfall in this code? Or is there serious performance penalty using co::IoEvent? Why isn't this the example in documents?

    PS: I have zero knowledge about SSL sockets, not clue if we have to do SSL_read() before SSL_get_error(). I only tested with POCO's SecureStreamSocket and it worked as well.

  • cannot build with msvc x86

    cannot build with msvc x86

    Under co/base/:

    $ xmake f -a x86
    checking for the Microsoft Visual Studio (x86) version ... 2019
    
    $ xmake
    [ 23%]: compiling.release co\impl\epoll.cc
    [ 26%]: compiling.release co\impl\co_win.cpp
    [ 29%]: compiling.release stack_trace\stack_trace_win.cpp
    [ 33%]: compiling.release win\time.cpp
    [ 39%]: compiling.release fast.cc
    [  6%]: compiling.release fastring.cc
    [  9%]: compiling.release hash\base64.cc
    [ 16%]: compiling.release co\impl\co_unix.cc
    [ 19%]: compiling.release json.cc
    [ 42%]: compiling.release co\impl\scheduler.cc
    [ 46%]: compiling.release unix\time.cc
    [ 49%]: compiling.release win\os.cpp
    [ 52%]: compiling.release str.cc
    error: time.cpp
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(46): error C3861: '_InterlockedIncrement64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(62): error C3861: '_InterlockedDecrement64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(78): error C3861: '_InterlockedExchangeAdd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(94): error C3861: '_InterlockedExchangeAdd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(110): error C3861: '_InterlockedExchangeAdd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(126): error C3861: '_InterlockedExchangeAdd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(142): error C3861: '_InterlockedExchangeAdd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(158): error C3861: '_InterlockedExchangeAdd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(174): error C3861: '_InterlockedOr64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(190): error C3861: '_InterlockedAnd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(206): error C3861: '_InterlockedXor64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(222): error C3861: '_InterlockedOr64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(238): error C3861: '_InterlockedAnd64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(254): error C3861: '_InterlockedXor64': identifier not found
    C:\Users\fzheng\source\repos\co\base\win/atomic.h(270): error C3861: '_InterlockedExchange64': identifier not found
    
  • 是否有意向将install后的库名以及目录名由base改为co?

    是否有意向将install后的库名以及目录名由base改为co?

    目前执行xmake install后,会将头文件放在base目录下,静态库被命名为libbase.abase这个名字太普通了,不够将库与程序内部的名字区分开。既然项目名叫co,何不将头文件放在include/co目录下,且库名为libco.alibco.so

    这个动静有点大,但从长远来看,我觉得有必要来执行这个改动。

  • macOS 平台 动态库hook不生效

    macOS 平台 动态库hook不生效

    目前的http::Client使用curl_easy_perform,这是一个阻塞接口。 使用单个协程调度器时,http请求将阻塞其他协程。

    http::Client应该设计成非阻塞协程的,这才能体现协程的优势。推广到其他API,作为协程库里的实现,应当都设计为非阻塞的~

    PS:

    1. 非阻塞可通过curl_multi_perform+辅助线程/协程(也许),或者有更好的办法(基于curl)?
    2. 很多测试貌似应该用单个协程调度器,比较容易发现阻塞的问题。
  • vcpkg conan 都找不到coost这个包,xmake编译出来也用不了

    vcpkg conan 都找不到coost这个包,xmake编译出来也用不了

    如题,我看readme里面写了这几种使用方式

    vcpkg search coost
    conan search coost -r all
    

    都找不到这个包

    另外,xmake.lua 直接引入coost后,

    add_requires("fmt", "coost", "conan::pugixml/1.12.1")
    add_packages("fmt", "coost", "conan::pugixml/1.12.1")
    

    在 ubuntu 编译示例代码也会报错

    #include "co/all.h"
    
    DEF_string(s, "nice", "");
    
    int main(int argc, char** argv) {
        flag::init(argc, argv);
        LOG << FLG_s;
        return 0;
    }
    

    会产生下面的错误

    [email protected] /m/c/m/c/cpp_practical_util> x
    [ 88%]: linking.debug test
    error: /usr/bin/ld: /home/cat/.xmake/packages/c/coost/v3.0.0/e7a64508b634445f93e6b7f099ab5e52/lib/libco.a(stack_trace.cc.o): in function `___::log::StackTraceImpl::dump_stack(void*, int)':
    stack_trace.cc:(.text+0xb8): undefined reference to `backtrace_create_state'
    /usr/bin/ld: stack_trace.cc:(.text+0xcf): undefined reference to `backtrace_full'
    collect2: error: ld returned 1 exit status
    
  • [help] co::go(): any easy and efficient way to send notices to all schedulers and/or all coroutines?

    [help] co::go(): any easy and efficient way to send notices to all schedulers and/or all coroutines?

    i have a program like this

    server.listen();
    while (server.poll())
        go([socket = socket.acceptConnection()]() mutable {
            char bytes[1024];
            while (int size = socket.receive(bytes, 1024))
            {
                // do something and write to socket
            }
        });
    

    this works perfectly for request-response pattern. but in situations where server push is also desired (like in subscribe-publish pattern, but work with request-response at the same time. ), what can i do if i dont wanna open up another connection and do different things? i dont think frequently sending "check" commands to server is a good idea.

    ps: im not using so for networking becuz it doesnt have built-in ssl support (yet).

  • unitest xmake错误:error: unknown target(base) for unitest.deps!

    unitest xmake错误:error: unknown target(base) for unitest.deps!

    我根据文档上的xmake编译步骤,编译co/unitest时报错 checking for the architecture ... x64 checking for the Microsoft Visual Studio (x64) version ... 2017 error: unknown target(base) for unitest.deps! 该如何解决

  • libcurl 版本冲突导致 http get 没有发送请求

    libcurl 版本冲突导致 http get 没有发送请求

        string URL = "http://github.com";
        auto req_lambda3 = [](shared_ptr<LambdaParams2> p)
        {
            http::Client c("http://github.com"); // https client to github.com:443
            std::cout << "1--nothing---------" << std::endl;
            c.get("/");
            std::cout << c.body() << c.strerror() << "2--nothing---------" << std::endl;
            std::cout << "3--nothing---------" << std::endl;
        };
        co::go(&req_lambda3, make_shared<LambdaParams2>(make_shared<http::Client>(URL.c_str()), make_shared<string>("asdk")));
        std::cout << "4--nothing---------" << std::endl;
        std::this_thread::sleep_for(10000ms);
    

    输出 4--nothing--------- │ 1--nothing---------

    抓包没有发送请求

    预期 应当 get 成功发送请求

    环境

    ubuntu18 amd64. g++ 5.5. c++14. libcurl 7.73.0.

  • arm7协程中opencv resize触发Bus error

    arm7协程中opencv resize触发Bus error

    #include <opencv2/imgproc.hpp>
    #include <opencv2/imgcodecs.hpp>
    #include <co/co.h>
    #include <co/log.h>
    
    DEC_bool(cout);
    
    int main(int argc, char** argv)
    {
        co::init();
        log::init();
    
        FLG_cout = true;
    
        co::WaitGroup wg;
    
        auto mat = cv::imread("./bar.jpeg", cv::IMREAD_UNCHANGED);
        cv::Mat tmp;
        cv::resize(mat, tmp, cv::Size(100, 100));
    
        LOG << "resize " << tmp.cols << " " << tmp.rows;
    
        go([wg, mat]{
            wg.add();
            cv::Mat tmp;
            cv::resize(mat, tmp, cv::Size(200, 200));
    
            LOG << "resize2 " << tmp.cols << " " << tmp.rows;
    
            wg.done();
        });
    
        wg.wait();
    
        return 0;
    }
    

    堆栈

    #0  cv::hal_baseline::v_int16x8::v_int16x8 (this=0x9fafd01c, v=...)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/core/include/opencv2/core/hal/intrin_neon.hpp:206
    #1  0xa4b53fd8 in cv::hal_baseline::v_load (ptr=0x9fb1e780)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/core/include/opencv2/core/hal/intrin_neon.hpp:1277
    #2  0xa4e1bcf0 in cv::HResizeLinearVecU8_X4::operator() (this=0x9fafd688, src=0x9fafd78c, 
        dst=0x9fafd74c, count=2, xofs=0x9fb1db00, alpha=0x9fb1e780, dmax=600, cn=3, xmax=600)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/imgproc/src/resize.cpp:1744
    #3  0xa4e4bd78 in cv::HResizeLinear<unsigned char, int, short, 2048, cv::HResizeLinearVecU8_X4>::operator() (this=0x9fafdbf8, src=0x9fafd78c, dst=0x9fafd74c, count=2, xofs=0x9fb1db00, 
        alpha=0x9fb1e780, swidth=3240, dwidth=600, cn=3, xmin=0, xmax=600)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/imgproc/src/resize.cpp:1830
    #4  0xa4e4357c in cv::resizeGeneric_Invoker<cv::HResizeLinear<unsigned char, int, short, 2048, cv::HResizeLinearVecU8_X4>, cv::VResizeLinear<unsigned char, int, short, cv::FixedPtCast<int, unsigned char, 22>, cv::VResizeLinearVec_32s8u> >::operator() (this=0x9fafdcfc, range=...)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/imgproc/src/resize.cpp:2167
    #5  0xa490fc04 in cv::parallel_for_impl (range=..., body=..., nstripes=0.6103515625)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/core/src/parallel.cpp:540
    #6  0xa490f9a8 in cv::parallel_for_ (range=..., body=..., nstripes=0.6103515625)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/core/src/parallel.cpp:506
    #7  0xa4e21438 in cv::resizeGeneric_<cv::HResizeLinear<unsigned char, int, short, 2048, cv::HResizeLinearVecU8_X4>, cv::VResizeLinear<unsigned char, int, short, cv::FixedPtCast<int, unsigned char, 22>, cv::VResizeLinearVec_32s8u> > (src=..., dst=..., xofs=0x9fb1db00, _alpha=0x9fb1e780, 
        yofs=0x9fb1e460, _beta=0x9fb1f0e0, xmin=0, xmax=600, ksize=2)
        at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/imgproc/src/resize.cpp:2204
    #8  0xa4e20268 in cv::hal::resize (src_type=16, 
    --Type <RET> for more, q to quit, c to continue without paging--c
        src_data=0x9ff25040 "4MQ-FJ)BF*CG0FK1GL3IN5KP6MO7OO2JJ1JF3NJ5QK5RI:VP9TQ0JJ7NP;RT0FK)?D.DJ2HN4GN5HO5HP2EM.AI.AI4GO9NV1HP+EL+CI.FL-EK)AG(@F,DJ.GK/HL/HL-FJ+DH+DH-FJ0IM/IO3MS5MS4LR6KS1FN0CK4GO0CK(;C/BI5HO,@E,@E2HM2IK3GH/DB,A"..., src_step=3240, src_width=1080, src_height=720, dst_data=0x9fb005c0 "", dst_step=600, dst_width=200, dst_height=200, inv_scale_x=0.18518518518518517, inv_scale_y=0.27777777777777779, interpolation=1) at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/imgproc/src/resize.cpp:4036
    #9  0xa4e209d8 in cv::resize (_src=..., _dst=..., dsize=..., inv_scale_x=0.18518518518518517, inv_scale_y=0.27777777777777779, interpolation=1) at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/opencv-src/modules/imgproc/src/resize.cpp:4089
    #10 0x000126c0 in <lambda()>::operator()(void) const (__closure=0x340d4) at /Volumes/Docs/git/cppframe/frameworks/wuyi_core/main.cpp:26
    #11 0x00014004 in co::xx::Function0<main(int, char**)::<lambda()> >::run(void) (this=0x340d0) at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/install/wuyi_util/include/co/closure.h:24
    #12 0xa6477230 in co::SchedulerImpl::main_func (from=...) at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/libco-src/src/co/scheduler.cc:38
    #13 0xa64b5b44 in tb_context_make () at /Volumes/Docs/git/cppframe/build-armeabihf-v7a-Debug/_deps/libco-src/src/co/context/context_arm.S:131
    
  • udpsocket  co::close无法让co::recvfrom跳出等待

    udpsocket co::close无法让co::recvfrom跳出等待

    co::close 触发了del_event(ev) 但是co::recvfrom等待的EV_read 消息订阅被删除,但是recvfrom仍然在等待。

    解决方法: 1、或许可以加入EV_close/EV_ignore之类的事件。 2、IoEvent加入多事件绑定,同时绑定EV_read和EV_close/EV_ignore。

  • 关于Json::Value::operator[]的疑问

    关于Json::Value::operator[]的疑问

    https://github.com/idealvin/co/blob/110eadde2c89dffa259a161c100cd4161253441f/base/json.cc#L15

    正常访问一个objectmember时,应该先调用has_member()来进行判断。但看上面函数的代码,如果直接使用[]来访问相关member,这里的逻辑似乎是打算支持这种行为?

    如果不支持的话,21&22行的意义何在呢? 如果支持的话,接下来访问其它member或者调用str()就会出错了。如以下代码:

    #include "co/json.h"
    
    int main() {
      auto v = json::parse("{\"name\": \"tiger\"}");
      v["n"];
      printf("%s\n", v["name"].str().c_str());
      return 0;
    }
    

    输出结果是null

  • SylixOS嵌入式实时操作系统上移植coost

    SylixOS嵌入式实时操作系统上移植coost

    编译器采用gcc-arm-none-eabi

    在编译context_arm.S时,出现如下问题

    make all arm-sylixos-eabi-gcc -mcpu=cortex-a9 -mno-unaligned-access -O0 -g3 -gdwarf-2 -Wall -fmessage-length=0 -fsigned-char -fno-short-enums -fno-strict-aliasing -x assembler-with-cpp -DSYLIXOS -D__linux__ -D__ARM_ARCH_7A__ -DSYLIXOS_LIB -I"D:\SylixOS_WS\workspace\coost/include" -I"D:/SylixOS_WS/workspace/ArmLite/libsylixos/SylixOS" -I"D:/SylixOS_WS/workspace/ArmLite/libsylixos/SylixOS/include" -I"D:/SylixOS_WS/workspace/ArmLite/libsylixos/SylixOS/include/network" -MMD -MP -MF ./Debug/dep/libcoost.so/src/co/context/context_arm.d -c src/co/context/context_arm.S -o Debug/obj/libcoost.so/src/co/context/context_arm.o src/co/context/context_arm.S: Assembler messages: src/co/context/context_arm.S:102: Error: bad instructionfunction tb_context_make,export=1' src/co/context/context_arm.S:142: Error: bad instruction endfunc' src/co/context/context_arm.S:152: Error: bad instructionfunction tb_context_jump,export=1' src/co/context/context_arm.S:204: Error: bad instruction endfunc' make: *** [Debug/obj/libcoost.so/src/co/context/context_arm.o] Error 1

    无法识别汇编代码中的 function 以及 endfunc

  • 有支持格式化字符串吗?

    有支持格式化字符串吗?

    支持格式化字符串,而不再需要用sprintf,例如folly库中的这种用法:

    using folly::format;
    using folly::sformat;
    
    // Objects produced by format() can be streamed without creating
    // an intermediary string; {} yields the next argument using default
    // formatting.
    std::cout << format("The answers are {} and {}", 23, 42);
    // => "The answers are 23 and 42"
    
    // If you just want the string, though, you're covered.
    std::string result = sformat("The answers are {} and {}", 23, 42);
    // => "The answers are 23 and 42"
    
    // To insert a literal '{' or '}', just double it.
    std::cout << format("{} {{}} {{{}}}", 23, 42);
    // => "23 {} {42}"
    
    // Arguments can be referenced out of order, even multiple times
    std::cout << format("The answers are {1}, {0}, and {1} again", 23, 42);
    // => "The answers are 42, 23, and 42 again"
    
    // It's perfectly fine to not reference all arguments
    std::cout << format("The only answer is {1}", 23, 42);
    // => "The only answer is 42"
    
    // Values can be extracted from indexable containers
    // (random-access sequences and integral-keyed maps), and also from
    // string-keyed maps
    std::vector<int> v {23, 42};
    std::map<std::string, std::string> m { {"what", "answer"} };
    std::cout << format("The only {1[what]} is {0[1]}", v, m);
    // => "The only answer is 42"
    
    // format works with pairs and tuples
    std::tuple<int, std::string, int> t {42, "hello", 23};
    std::cout << format("{0} {2} {1}", t);
    // => "42 23 hello"
    
    // Format supports width, alignment, arbitrary fill, and various
    // format specifiers, with meanings similar to printf
    // "X<10": fill with 'X', left-align ('<'), width 10
    std::cout << format("{:X<10} {}", "hello", "world");
    // => "helloXXXXX world"
    
    // Field width may be a runtime value rather than part of the format string
    int x = 6;
    std::cout << format("{:-^*}", x, "hi");
    // => "--hi--"
    
    // Explicit arguments work with dynamic field width, as long as indexes are
    // given for both the value and the field width.
    std::cout << format("{2:+^*0}",
    9, "unused", 456); // => "+++456+++"
    
    // Format supports printf-style format specifiers
    std::cout << format("{0:05d} decimal = {0:04x} hex", 42);
    // => "00042 decimal = 002a hex"
    
    // Formatter objects may be written to a string using folly::to or
    // folly::toAppend (see folly/Conv.h), or by calling their appendTo(),
    // and str() methods
    std::string s = format("The only answer is {}", 42).str();
    std::cout << s;
    // => "The only answer is 42"
    
    // Decimal precision usage
    std::cout << format("Only 2 decimals is {:.2f}", 23.34134534535);
    // => "Only 2 decimals is 23.34"
    
  • add HTTP long-conn-session support

    add HTTP long-conn-session support

    添加对http long-connection session模式的支持。即一直保持http连接,并且response不断追加发送数据的工作模式。 此模式常用于需要保持连接完成大量数据发送(如发送超长文件)或者数据不定时发送(如:视频实时推流,x-mixed-replace,部分web-socket应用场景等)。 主要改动(API接口部分): 1、在Http Response类(Res)中,新增一个send_body方法。此方法可在设置完header(add_header)后使用。用户每次调用send_body将即时发送一批body数据(因此,第一次调用send_body会附加Http response header的发送)。用户可以在保证当前协程函数(on_req)不退出的情况下任意多次调用send_body,直至业务数据发送完毕或者出错(send_body返回非0)。无论出错还是正常完成,退出当前协程函数即完成本http session资源的清理。 2、因为send_body(长连接)模式与set_body(短链接)模式互斥,因此修改set_body函数返回值为bool。用户调用set_body以后将无法调用send_body,同理用户调用send_body以后也将无法调用set_body(返回false)。 实现部分改动: 在Response-ctx类实现中,增加3个成员:

    • tcp::Connection pc_; //存放本http Session socket connection的指针。短连接时用不到,仅在长连接模式下使用
    • header_send; //header是否发送的状态码。初始化为0,表示header未处理。为-1表示header已经pack但未发送(短链接模式),为1表示header已经发送(长连接模式)。
    • s_err:仅用于长连接模式,表示是否有socket_error。
Coroutine - C++11 single .h asymmetric coroutine implementation via ucontext / fiber

C++11 single .h asymmetric coroutine implementation API in namespace coroutine: routine_t create(std::function<void()> f); void destroy(routine_t id);

Nov 16, 2022
Cpp-concurrency - cpp implementation of golang style concurrency

cpp-concurrency C++ implementation of golang style concurrency Usage Use existing single header concurrency.hpp or run script to merge multiple header

Aug 11, 2022
:copyright: Concurrent Programming Library (Coroutine) for C11

libconcurrent tiny asymmetric-coroutine library. Description asymmetric-coroutine bidirectional communication by yield_value/resume_value native conte

Sep 2, 2022
Single header asymmetric stackful cross-platform coroutine library in pure C.
Single header asymmetric stackful cross-platform coroutine library in pure C.

minicoro Minicoro is single-file library for using asymmetric coroutines in C. The API is inspired by Lua coroutines but with C use in mind. The proje

Nov 30, 2022
A C++20 coroutine library based off asyncio
A C++20 coroutine library based off asyncio

kuro A C++20 coroutine library, somewhat modelled on Python's asyncio Requirements Kuro requires a C++20 compliant compiler and a Linux OS. Tested on

Nov 9, 2022
C++20 Coroutine-Based Synchronous Parser Combinator Library

This library contains a monadic parser type and associated combinators that can be composed to create parsers using C++20 Coroutines.

Oct 13, 2022
Cppcoro - A library of C++ coroutine abstractions for the coroutines TS

CppCoro - A coroutine library for C++ The 'cppcoro' library provides a large set of general-purpose primitives for making use of the coroutines TS pro

Nov 29, 2022
C++14 coroutine-based task library for games

SquidTasks Squid::Tasks is a header-only C++14 coroutine-based task library for games. Full project and source code available at https://github.com/we

Nov 30, 2022
Powerful multi-threaded coroutine dispatcher and parallel execution engine

Quantum Library : A scalable C++ coroutine framework Quantum is a full-featured and powerful C++ framework build on top of the Boost coroutine library

Nov 28, 2022
Async GRPC with C++20 coroutine support

agrpc Build an elegant GRPC async interface with C++20 coroutine and libunifex (target for C++23 executor). Get started mkdir build && cd build conan

Nov 15, 2022
Mx - C++ coroutine await, yield, channels, i/o events (single header + link to boost)

mx C++11 coroutine await, yield, channels, i/o events (single header + link to boost). This was originally part of my c++ util library kit, but I'm se

Sep 21, 2019
Elle - The Elle coroutine-based asynchronous C++ development framework.
Elle - The Elle coroutine-based asynchronous C++ development framework.

Elle, the coroutine-based asynchronous C++ development framework Elle is a collection of libraries, written in modern C++ (C++14). It contains a rich

Nov 19, 2022
Go-style concurrency in C

LIBMILL Libmill is a library that introduces Go-style concurrency to C. Documentation For the documentation check the project website: http://libmill.

Nov 29, 2022
Libgo - Go-style concurrency in C++11
Libgo - Go-style concurrency in C++11

libgo libgo -- a coroutine library and a parallel Programming Library Libgo is a stackful coroutine library for collaborative scheduling written in C+

Nov 28, 2022
Bolt is a C++ template library optimized for GPUs. Bolt provides high-performance library implementations for common algorithms such as scan, reduce, transform, and sort.

Bolt is a C++ template library optimized for heterogeneous computing. Bolt is designed to provide high-performance library implementations for common

Nov 27, 2022
oneAPI DPC++ Library (oneDPL) https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/dpc-library.html

oneAPI DPC++ Library (oneDPL) The oneAPI DPC++ Library (oneDPL) aims to work with the oneAPI DPC++ Compiler to provide high-productivity APIs to devel

Dec 3, 2022
Simple and fast C library implementing a thread-safe API to manage hash-tables, linked lists, lock-free ring buffers and queues

libhl C library implementing a set of APIs to efficiently manage some basic data structures such as : hashtables, linked lists, queues, trees, ringbuf

Nov 19, 2022
OOX: Out-of-Order Executor library. Yet another approach to efficient and scalable tasking API and task scheduling.

OOX Out-of-Order Executor library. Yet another approach to efficient and scalable tasking API and task scheduling. Try it Requirements: Install cmake,

Oct 25, 2022