xhawk18 / promise-cpp

C++ promise/A+ library in Javascript style.
MIT License
672 stars 92 forks source link

嵌套promise在析构时候会抛异常 #16

Open Cirnoo opened 2 years ago

Cirnoo commented 2 years ago

test0.cpp中有如下示例

.then([&next](){
        output_func_name();
        next= newPromise([](Defer d) {
            output_func_name();
            //尝试调用d.resolve(1, 'c');
        });
        //尝试调用 next.resolve();,或next.resolve(1, 'c');
        //Will call next.resole() or next.reject() later
        //throw 33;
        //next.reject(55, 66);
        return next;
    })

如果增加next.resolve();或者d.resolve(); 会产生bad_anycast异常,导致`promiseHolder->state = TaskState::kRejected`,在析构时会走到全局异常handler中。

我想通过创建一个新的newPromise的方式,内部切线程异步处理完成后再回调到下个then,这样看起来会有问题。

xhawk18 commented 2 years ago

抓到异常是对的,因为resolve/reject需要下一级的 then/fail 函数捕获。 如果参数类型不一样,无法捕获,就抛异常了。可以这样试下

 .then([&next](){
        output_func_name();
        next = newPromise([](Defer d) {
            output_func_name();
        });
        next.resolve(1, 'c');
        return next;
    }).then([](int a, char b) {
        printf("a = %d, b = %d\n", a, (int)b);
    })

或者捕获任意参数类型,可以将 a, b参数去掉

 .then([&next](){
        output_func_name();
        next = newPromise([](Defer d) {
            output_func_name();
        });
        next.resolve(1, 'c');
        return next;
    }).then([]() {
        printf("运行到这里\n");
    })
xhawk18 commented 2 years ago

线程切换回来再调用,应该问题不大。 因为:

  1. 任务链实例析构时,代码会根据需要做出判断,是否要调用 ”全局异常handler“。只要保证任务链实例还在,就不会走到全局异常。

  2. next或d内部,都通过shared_ptr的方式,保存了任务链实例。

  3. 线程切换回来调用,必定要保障 next或d至少有一个(或其复制品)还能访问到。(对比一楼的状况,next和d都被析构了,内部的任务链也析构了,于是走到全局异常。)

Cirnoo commented 2 years ago

感谢你的回复,除了你指出的问题,还有是示例代码后面的then类型未匹配

.then([](int n, char c) {
        output_func_name();
        printf("n = %d, c = %c\n", (int)n, c);
    }).then([](char n) {
        output_func_name();
        printf("n = %d\n", (int)n);
    })

第一个then的return是void和第二个then的入参不一致~,补充上resolve('0')就没有异常了