Giter Site home page Giter Site logo

idealvin / coost Goto Github PK

View Code? Open in Web Editor NEW
3.8K 129.0 553.0 3.18 MB

A tiny boost library in C++11.

License: Other

Shell 0.02% C 2.42% C++ 91.50% Assembly 4.41% Lua 0.36% CMake 0.49% Dockerfile 0.10% Makefile 0.19% LLVM 0.21% Yacc 0.30%
config coroutine json log rpc unit-test benchmark

coost's Issues

Question about set_cloexec

inline void set_cloexec(sock_t fd) {
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_EXCL);
}

O_EXCL or FD_CLOEXEC ?

关于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

Document that fastring is not thread-safe

The implementation of fastring is not thread-safe. That’s fine, but people might get in trouble if they don’t know this, since std::string is thread-safe. So it would be good to point this out in the documentation.

(Making fastring thread safe is probably not a good idea. I’ve read that std::string used to use ref-counting and copy-on-write the way yours does, but the atomic operations or mutexes needed to make it thread-safe hurt performance a lot, and it’s actually faster for it to always copy.)

JSON实现不符合ECMA-404

string没有实现\uxxxx形式的unicode转义,以及\b \f的转义。

看实现实在没法看出来为什么会比rapidJSON性能高,而rapidJSON甚至都用上了SIMD优化,麻烦给出benchmark?

Error: Unrecognized Exception

将co log编入dll,使用c#调用,.log文件中会缺失很多条log,并且会产生.fatal文件,.fatal文件事例如下:

1216 22:30:33] Error: Unrecognized Exception
D:\Project\co\base\stack_trace\StackWalker.cpp (1096): StackWalker::ShowCallstack
D:\Project\co\base\stack_trace\stack_trace_win.cpp (203): `anonymous namespace'::StackTraceImpl::on_exception
00007FFBA96B78D8 (ntdll): (filename not available): RtlInitializeCriticalSection
00007FFBA965D4FA (ntdll): (filename not available): RtlWalkFrameChain
00007FFBA965BE9A (ntdll): (filename not available): RtlRaiseException
00007FFBA671A388 (KERNELBASE): (filename not available): RaiseException
00007FFB54122413 (mono-2.0-bdwgc): (filename not available): mono_native_thread_set_name
00007FFB541D3B60 (mono-2.0-bdwgc): (filename not available): mono_thread_set_manage_callback
00007FFB541DC685 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D57E8 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D5576 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFBA8134034 (KERNEL32): (filename not available): BaseThreadInitThunk
00007FFBA96C3691 (ntdll): (filename not available): RtlUserThreadStart

1216 22:30:33] Error: Unrecognized Exception
D:\Project\co\base\stack_trace\StackWalker.cpp (1096): StackWalker::ShowCallstack
D:\Project\co\base\stack_trace\stack_trace_win.cpp (203): `anonymous namespace'::StackTraceImpl::on_exception
00007FFBA96B78D8 (ntdll): (filename not available): RtlInitializeCriticalSection
00007FFBA965D4FA (ntdll): (filename not available): RtlWalkFrameChain
00007FFBA965BE9A (ntdll): (filename not available): RtlRaiseException
00007FFBA671A388 (KERNELBASE): (filename not available): RaiseException
00007FFB54122413 (mono-2.0-bdwgc): (filename not available): mono_native_thread_set_name
00007FFB541D3B60 (mono-2.0-bdwgc): (filename not available): mono_thread_set_manage_callback
00007FFB541D8B0B (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541DB231 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D57E8 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D5576 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFBA8134034 (KERNEL32): (filename not available): BaseThreadInitThunk
00007FFBA96C3691 (ntdll): (filename not available): RtlUserThreadStart

dtoa很慢

做了一个测试,发现对于double类型转为字符串,速度超级慢

const size_t N = 10000000;

template<typename T>
void benchPrintf(const char* fmt) {

    TimeStamp start = TimeStamp::now();
    char buf[32];
  
    for (size_t i = 0; i < N; ++i)
        snprintf(buf, sizeof buf, fmt, (T)(i));

    TimeStamp end = TimeStamp::now();
    printf("benchPrintf %f\n", timeDifference(end, start));
}

template<typename T>
void benchStringStream() {

    TimeStamp start = TimeStamp::now();
    std::ostringstream os;

    for (size_t i = 0; i < N; ++i) {
        os << (T)(i);
        os.seekp(0, std::ios_base::beg);
    }

    TimeStamp end = TimeStamp::now();
    printf("benchStringStream %f\n", timeDifference(end, start));
}

template<typename T>
void benchStream() {

    TimeStamp start = TimeStamp::now();
    FStream os;
    for (size_t i = 0; i < N; ++i) {
        os << (T)(i);
        os.clear();
    }
    TimeStamp end = TimeStamp::now();
    printf("benchStream %f\n", timeDifference(end, start));
}

int main()
{

  puts("int");
  benchPrintf<int>("%d");
  benchStringStream<int>();
  benchStream<int>();

  puts("double");
  benchPrintf<double>("%.12g");
  benchStringStream<double>();
  benchStream<double>();

  puts("int64_t");
  benchPrintf<int64_t>("%" PRId64);
  benchStringStream<int64_t>();
  benchStream<int64_t>();

  puts("void*");
  benchPrintf<void*>("%p");
  benchStringStream<void*>();
  benchStream<void*>();
}

release下执行vs2015 logTest文件报错

FLOG << "This is FLOG (fatal).. " << 23;
执行这句的时候报错
0x00007FFFD0CCE91E (ucrtbase.dll) (**.exe 中)处有未经处理的异常: 请求了严重的程序退出。
想问下是什么情况导致的?
代码和设置没有做任何更改

关于LruMap的疑问

// The key is not inserted if it already exists.
void insert(const K& key, const V& value) {
      auto r = _kv.insert(std::make_pair(key, value));
      if (!r.second) return;

      _kl.push_front(key);
      _ki[key] = _kl.begin();

      if (_kv.size() > _capacity) {
          K k = _kl.back();
          _kl.pop_back();
          _kv.erase(k);
          _ki.erase(k);
      }
}

当缓存中已有key时,insert不会有任何操作,如果我想更新一个key的value时该怎么办,并且_kl中的顺序也要改变。

random.h中的一些疑惑

uint32_t next() {
static const uint32_t M = 2147483647L; // 2^31-1
static const uint64_t A = 16385; // 2^14+1

// Computing _seed * A % M.
uint64_t p = _seed * A;
_seed = static_cast<uint32_t>((p >> 31) + (p & M));
if (_seed > M) _seed -= M;

return _seed;
}

其中if (_seed > M) _seed -= M; 这行是不是多余的, 因为M本来就是uint32_t的最大值, 上面一行强转uint32_t之后不能大于M, if这条语句是不可能走到的

arm gcc编译器无法通过编译, 需要将char 改成int8_t

index 9d2a6e3..c09f622 100644
--- a/src/hash/base64.cc
+++ b/src/hash/base64.cc
@@ -3,7 +3,7 @@
static const char* entab =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

-static const char detab[256] = {
+static const int8_t detab[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,

co:Event wait()不带参数,无法唤醒

#include "co/co.h"
#include "co/log.h"
#include "co/time.h"

co::Event ev;

DEF_bool(wait_alway, true, "false: wait for timeout, true wait alway");
void f2(){
    CLOG << "f2() start";
    bool r = true;
    if (FLG_wait_alway) {
        ev.wait();
    } else {
        r = ev.wait(1*1000);
    }
    CLOG << "f2() end: " << r;
}

void f3() {
    CLOG << "f3() start";
    ev.signal();
    CLOG << "f3() end";
}

int main(int argc, char** argv) {
    flag::init(argc, argv);
    log::init();
    go(f2);
    sleep::ms(100);
    go(f3);

    sleep::ms(2*1000);
    return 0;
}

运行结果1:
./test wait_alway=false

f2() start
f3() start
f3() end
f2() end: true

运行结果1:
./test wait_alway=true

f2() start
f3() start
f3() end

关于定长整数类型

本库引入了定长整数类型别名。但有一些处理让我觉得困惑:

  • fastring 的内部引用计数类需要假定
    unsigned int 的长度;
  • Random 的整个操作看起来需要依赖标准整数类型的长度;
  • 以及可能存在的其他依赖标准整数类型长度的实现。

这些地方是不是直接使用定长整数类型别名更好?

其次,本库的定长整数类型依赖了 <stdint.h> 。它是 C99/C++11 起的标准库头文件,即使 MSVC 也支持。
是否考虑在此方面移除对 _MSC_VER 的检测?

关于 `thread_ptr` 的疑问

@idealvin 你好。

按我的理解,当 thread_ptr 的对象,例如 foo,以 std::ref(foo) 的方式传进线程函数之后,子线程是无法获取父线程设置的指针值的。也就是说,任何一个线程要使用 foo,都必须现在线程内设置 foo 指向的对象才能使用。

既然如此,为什么不在每个线程里分别使用 std::unique_ptr 呢?使用 thread_ptr 的好处在哪里?

Lru 实现

插入发现存在是不是调整一下位置到头部?
list用了2个使用一个效率会更好一点?
//一般插入实现大致这样

void put(const Key& key,const Value& value){
	const auto iter = _cache.find(key);
	if(iter!= _cache.end()){
		// 找到了就更新value,并提取到最前面
		iter->second->value = value;
		//move iter->second to _keys' begin postion
		_keys.splice(_keys.begin(),_keys,iter->second);
		return;
	}
	_keys.emplace_front(key,value);
	_cache[key] = _keys.begin();
	resize();
}

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

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

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

如何更改配置的值

类似于文档的这种 日志输出的位置,日志文件名字,应该如何设置呢?

`//日志打印输出的位置
DEF_string(log_dir, "../log", "Log dir, will be created if not exists");
//日志文件名
DEF_string(log_file_name, "acl_log", "name of log file, using exename if empty");
//日志打印级别
DEF_int32(min_log_level, 0, "write logs at or above this level, 0-4 (debug|info|warning|error|fatal)");
//输出到终端
DEF_bool(cout, true, "also logging to terminal");

DEF_int32(co_sched_num, 100, "协程栈大小,每个调度线程都会分配一个栈,调度线程内的协程共用这个栈。");
DEF_int32(co_max_recv_size, 2, "一次能接收的最大数据长度,默认为 1M,超过此大小,分批接收。");
DEF_int32(co_max_send_size, 2, "一次能发送的最大数据长度,默认为 1M,超过此大小,分批发送");`

fastring 的原位构造函数

现版本的 fastring 拥有直接利用未被管理的内存的构造函数。看起来此构造函数得到使用的地方看起来很少(目前只注意到此处),而且写法上没有体现原位构造的特征。

我个人认为把它改成 static 成员函数(如 fastring::from_raw_buffer )或者友元自由函数(如 friend raw_buffer_to_fastring )会让用户更谨慎而安全地使用。

另外,或许只把此功能作为内部实现而非作为公开 API 也是一种选择。

rpc test失败

环境:vs2019
问题:运行rpc test程序时出现错误map/set iterators incompatible

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

关于 C++11 特性的考虑

目前看来这些代码并没有按照 C++11 前和 C++11 开始条件编译。假如这是有意的,那么我认为有些细节实现应当继续改进:

  • def.h 应当直接使用 <cstdint> 或者 <stdint.h> 。其他代码应该直接使用 (u)intN_t 以减少冲突。
  • 应该使用标准的 thread_local 代替 __thread
  • 原子对象应当使用 <atomic>
  • swap 函数和移动特殊成员函数应当加上 noexcept
    (以及其他可能存在的问题)

fastring: 多线程问题与内存管理问题

  1. fastring 类的引用计数未使用原子对象。这显然会造成多线程同时修改时的数据竞争。希望作者注明这种设计是否有意的。
  2. fastring 类的内存分配、释放函数是不能替换的。我认为替换全局的 operator newoperator delete 是在一定应用条件下提高性能的做法,但 fastring 并不能从中受益。

能否给个CMAKE的编译脚本

能否给个CMAKE的编译脚本,最好在alpine的环境下也能编译通过,github上很多库我在制作alpine镜像时候都碰到各种问题

windows 上 dll 调试模式下程序崩溃,Debug Assertion Failed!

只要我使用 co::sleep 函数就会报错
co 使用cmake 编译得 然后引入了 头文件 和LIB文件
使用官方的 client 代码示例

`

sock_t fd = co::tcp_socket();
struct sockaddr_in addr;
co::init_ip_addr(&addr, "127.0.0.1", 7788);
co::connect(fd, &addr, sizeof(addr), 3000);
co::set_tcp_nodelay(fd);
char buf[8] = { 0 };
for (int i = 0; i < 7; ++i) {
    co::sleep(1000);
    LOG << "send ping";
    co::send(fd, "ping", 4);
    co::recv(fd, buf, 4);
    LOG << "recv " << buf;
}
co::close(fd);

`

co::connect 填写第4个参数会报错 崩溃
co::sleep 也会报错 崩溃

错误提示
Debug Assertion Failed!

Program: E:\fiber\exiecheng\coroutine\Debug\testdll.exe
File: D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.26.28801\include\xtree
Line: 229

Expression: map/set iterators incompatible

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)

`json::Value::str()`不能正确地序列化某些浮点数值

当JSON字符串中含有1.0之类的数值时,json::Value::str()会将其序列化为1,这与原来该字段的类型不符,如果多次依次执行序列化、反序列化操作,会导致断言。

版本:Commit 95535b3 之前都有此现象
系统:Debian 10(Windows未测试)
内核:5.4.0-1-amd64

示例

#include <stdio.h>

#include "base/json.h"

fastring s = "{\"value\": 12.0}";

int main(int argc, char** argv) {
    auto j1 = json::parse(s);
    auto j2 = json::parse(j1.str());

    printf("j1 value: %f\n", j1["value"].get_double());
    printf("j2 value: %f\n", j2["value"].get_double());

    return 0;
}

执行结果

j1[0]: 12.000000
j_test: ./base/json.h:226: double json::Value::get_double() const: Assertion `this->is_double()' failed.
error: execv(/home/tiger/Codes/co/build/linux/x86_64/release/j_test) failed(-1)!

原因:序列化操作使用了fast::dtoa(),而fast::dtoa()在输出浮点时使用了Conversion Specifier g,这会导致尾部的0会被移除。这样就造成了类型不一致的问题。

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。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.