Exemplo n.º 1
0
int main()
{
    // 使用关键字go创建协程, go后面可以使用:
    //     1.void(*)()函数指针, 比如:foo.
    //     2.也可以使用无参数的lambda, std::bind对象, function对象, 
    //     3.以及一切可以无参调用的仿函数对象
    //   注意不要忘记句尾的分号";".
    go foo;

    go []{
        printf("lambda\n");
    };

    go std::bind(&A::fA, A());

    std::function<void()> fn(std::bind(&A::fB, A()));
    go fn;

    // 也可以使用go_stack创建指定栈大小的协程
    //   创建拥有10MB大栈的协程
    go_stack(10 * 1024 * 1024) []{
        printf("large stack\n");
    };

    // 协程创建以后不会立即执行,而是暂存至可执行列表中,等待调度器调度。
    // co_sched是全局唯一的协程调度器,有以下接口可以调度协程:
    //   1.Run 执行单次调度, 返回本次执行的协程数量
    //   2.RunLoop 无限循环执行Run, 不会返回
    //   3.RunUntilNoTask 循环执行Run, 直至协程数量为零.
    //
    // 当仅使用一些线程进行协程调度时, 协程地执行会严格地遵循其创建顺序.
    co_sched.RunUntilNoTask();
    return 0;
}
Exemplo n.º 2
0
static void fiber_accept(acl::server_socket& ss)
{
    __fiber_accept = acl_fiber_running();

    while (true)
    {
        // 等待接收客户端连接
        acl::socket_stream* conn = ss.accept();
        if (conn == NULL)
        {
            printf("accept error %s\r\n", acl::last_serror());
            break;
        }

        // 创建处理客户端对象的协程
        go_stack(STACK_SIZE) [=] {
            __nclients++;
            fiber_client(conn);
        };
    }
}
Exemplo n.º 3
0
static void fiber_client(acl::socket_stream* conn)
{
    // 创建客户端对象
    user_client* client = new user_client(*conn);

    // 创建从客户端连接读取数据的协程
    go_stack(STACK_SIZE) [=] {
        __nreader++;
        fiber_reader(client);
    };

    // 等待该客户端连接对象退出
    client->wait_exit();

    printf("----- client (%s), exit now -----\r\n", client->get_name());

    // 删除客户端对象及客户端连接对象
    delete client;
    delete conn;

    printf("----__nclients: %d-----\r\n", --__nclients);
    printf("----dead fibers: %d---\r\n", acl_fiber_ndead());
}
Exemplo n.º 4
0
int main()
{
    // 使用关键字go创建协程, go后面可以使用:
    //     1.void(*)()函数指针, 比如:foo.
    //     2.也可以使用无参数的lambda, std::bind对象, function对象, 
    //     3.以及一切可以无参调用的仿函数对象
    //   注意不要忘记句尾的分号";".
    go foo;

    go []{
        printf("lambda\n");
    };

    go std::bind(&A::fA, A());

    std::function<void()> fn(std::bind(&A::fB, A()));
    go fn;

    // 也可以使用go_stack创建指定栈大小的协程
    //   创建拥有10MB大栈的协程
    go_stack(10 * 1024 * 1024) []{
        printf("large stack\n");
    };

    // 协程创建以后不会立即执行,而是暂存至可执行列表中,等待调度器调度。
    // co_sched是全局唯一的协程调度器,有以下接口可以调度协程:
    //   1.Run 执行单次调度, 返回本次执行的协程数量
    //   2.RunLoop 无限循环执行Run, 不会返回
    //   3.RunUntilNoTask 循环执行Run, 直至协程数量为零.
    //
    // 当仅使用一个线程进行协程调度时, 协程地执行会严格地遵循其创建顺序.
    co_sched.RunUntilNoTask();

    // 多线程模式下, libgo还支持指定协程初始运行于哪个线程
    // 使用go_dispatch关键字来创建协程, 可以分派协程执行的线程.
    // 支持多种分派模式
    // 1.指定线程索引分派 (线程索引从0起, 按照调用Run的顺序决定线程索引)
    go_dispatch(2) []{
        printf("dispatch to thread[2] run\n");
    };
    // 2.随机 (调用过Run的线程才会参与随机指派)
    go_dispatch(egod_random) []{
        printf("random run\n");
    };
    // 3.robin算法 (调用过Run的线程, 或强制执行线程索引分派过协程的线程, 才会参与随机指派)
    go_dispatch(egod_robin) []{
        printf("robin run\n");
    };
    // 4.尽量置于当前线程 (只有当当前线程已经调用过Run后才生效)
    go_dispatch(egod_local_thread) []{
        printf("local thread run\n");
    };

    // 启动额外两个线程和主线程一起调度
    boost::thread_group tg;
    for (int i = 0; i < 2; ++i)
        tg.create_thread([]{ co_sched.RunUntilNoTask(); });
    co_sched.RunUntilNoTask();
    tg.join_all();

    // 默认配置下, 多线程调度时会采用worksteal算法做负载均衡, dispatch指定的协程也可能被其他
    // 线程偷走, 如果不希望被偷走, 可以关闭worksteal算法.
    co_sched.GetOptions().enable_work_steal = false;    // 关闭worksteal负载均衡算法

    return 0;
}
Exemplo n.º 5
0
static void fiber_reader(user_client* client)
{
    acl::socket_stream& conn = client->get_stream();
    conn.set_rw_timeout(0);

    client->set_reader();
    client->set_reading(true);

    // 登入服务器
    if (client_login(client) == false)
    {
        client->set_reading(false);
        printf("----------client_logout-------\r\n");

        // 失败,则退出客户端
        client_logout(client);

        printf("----__nreader: %d-----\r\n", --__nreader);
        return;
    }

    // 登入成功,则创建写协程用来向客户端发送消息
    go_stack(STACK_SIZE) [&] {
        __nwriter++;
        fiber_writer(client);
    };

    conn.set_rw_timeout(0);

    bool stop = false;
    acl::string buf;

    // 从客户端循环读取消息
    while (true)
    {
        bool ret = conn.gets(buf);
        if (ret == false)
        {
            printf("%s(%d): user: %s, gets error %s, fiber: %d\r\n",
                   __FUNCTION__, __LINE__, client->get_name(),
                   acl::last_serror(), acl_fiber_self());

            // 客户端退出
            if (client->exiting())
            {
                printf("----exiting now----\r\n");
                break;
            }

            if (errno == ETIMEDOUT)
            {
                if (conn.write("ping\r\n") == -1)
                {
                    printf("ping error\r\n");
                    break;
                }
            }
            else if (errno == EAGAIN)
                printf("EAGAIN\r\n");
            else {
                printf("gets error: %d, %s\r\n",
                       errno, acl::last_serror());
                break;
            }

            continue;
        }

        if (buf.empty())
            continue;

        // 分析客户端发送的消息,交由不同的处理过程
        std::vector<acl::string>& tokens = buf.split2("|");

        // 本客户端要求退出
        if (tokens[0] == "quit" || tokens[0] == "exit")
        {
            conn.write("Bye!\r\n");
            break;
        }

        // 本客户端发送聊天消息
        else if (tokens[0] == "chat")
        {
            if (client_chat(client, tokens) == false)
                break;
        }

        // 本客户端踢出其它客户端
        else if (tokens[0] == "kick")
        {
            if (client_kick(client, tokens) == false)
                break;
        }

        // 要求整个服务进程退出
        else if (tokens[0] == "stop")
        {
            stop = true;
            break;
        }
        else
            printf("invalid data: %s, cmd: [%s]\r\n",
                   buf.c_str(), tokens[0].c_str());
    }

    printf(">>%s(%d), user: %s, logout\r\n", __FUNCTION__, __LINE__,
           client->get_name());

    client->set_reading(false);

    // 退出客户端
    client_logout(client);

    printf("----__nreader: %d-----\r\n", --__nreader);

    if (stop)
    {
        int dumy = 1;
        // 如果要停止服务,则通知监控协程
        __chan_monitor.put(dumy);
    }
}