Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于 copp::coroutine_context_default::ptr_t 的疑问 #23

Closed
philGemini opened this issue Nov 25, 2021 · 8 comments
Closed

关于 copp::coroutine_context_default::ptr_t 的疑问 #23

philGemini opened this issue Nov 25, 2021 · 8 comments
Assignees
Labels

Comments

@philGemini
Copy link

`
#include <libcopp/coroutine/coroutine_context_container.h>
typedef copp::coroutine_context_default coroutine_t;

void download_other_thread(copp::coroutine_context* ctx)
{
std::this_thread::sleep_for(std::chrone::second(6));
ctx->resume();
}

int co_download(void ){
copp::coroutine_context
ctx = copp::this_coroutine::get_coroutine();
thread_pool::add(download_other_thread, ctx); // 其他线程处理具体的逻辑
ctx->yield();

printf("done!\n");

}

int main () {
for (int i= 0;i< 5;++i){
coroutin_t::ptr_t context = coroutine_t::create(co_download);
context->start();
// context.detach();
}

for (;;){}
return 0 

}
`

我希望是co_download 时候抛给其他线程处理,yield, 然后其他线程处理后 resume
但是这样是会抛错的, 因为 context 已经析构了
我看到 copp::this_coroutine::get_coroutine() 其实就是 context.get()
所以 context.detach() 后是可以的

但是这样疑惑就是 这个 ptr 我怎么主动 delete ? 还是说不用管?

我觉得你的框架非常好用, 就是这个疑问我一直困扰着.
不知都是不是我的使用思路有问题, 如果是的话, 上面那个需求怎么实现 ?
谢谢

@owent
Copy link
Owner

owent commented Nov 25, 2021

我希望是co_download 时候抛给其他线程处理,yield, 然后其他线程处理后 resume

这个协程库不提供线程池实现哈,所以你可以很容易地接入到框架原有的线程模型中。ptr_t是一个智能指针,直接通过框架已有的数据传递机制传到另一个线程就可以了。
比如有些框架会用无锁队列,也有些框架会通过某种消息机制传递,都是可以的。

我看到 copp::this_coroutine::get_coroutine() 其实就是 context.get()

this_* 类的接口本质上是使用了TLS数据区来保存了当前正在执行的协程指针。如果不在任何协程中,是会返回nullptr的。

但是这样疑惑就是 这个 ptr 我怎么主动 delete ? 还是说不用管?

只要引用计数不为0,就不会析构。引用计数为0的时候会自动析构,你不用管的。

BTW: 建议要安全得使用这个协程库,最简单得还是直接用 cotask 哈。接口和context类似的。

@philGemini
Copy link
Author

philGemini commented Nov 25, 2021

我使用的thread_pool 是我自己实现的,
我试过cotask 的, 同样问题也是 intrusive_ptr 的析构问题, 其实都是一样的
看到你的 ptr_t其实就是类似 boost::的instrutve_ptr, 但是不能手动 add_refcount
void download_other_thread(copp::coroutine_context ctx)
{
...
ctx->resume();
//这个时候 ctx由于 ptr_t 的离开 for loop 而回收了, 所以这里是报错的, Segmentation fault
}

int co_download(void ){
copp::coroutine_context* ctx = copp::this_coroutine::get_coroutine();
thread_pool::add(download_other_thread, ctx); // 其他线程处理具体的逻辑
ctx->yield();

printf("done!\n"); 
//delete ctx; // 这样是不行的 这里会报错  Segmentation fault

} // 这里我打印过

int main () {
for (int i= 0;i< 5;++i){
coroutin_t::ptr_t context = coroutine_t::create(co_download);
context->start();
// context.detach();

	这里我似乎没有任何办法把 这个 ptr_t 传给 co_download  , 
	而这里ptr_t 就析构了 , 导致在  download_other_thread 里面的 resume() 里直接报错
}

}

现在就是如果不detach 我就要保留全局引用, 而且 ptr_t 的 copy constructor 好像也是 delete 的
也不能放到 std::vector<>

而detach的话, 似乎我没有任何的办法 确保 copp::coroutine_context* 能否释放, 所以我在想我这种用法是否有问题.
如果可以的话,能否麻烦给个 伪代码 sample 给个思路 , 谢谢啊.

PS, 我这里没有用boost

@owent
Copy link
Owner

owent commented Nov 25, 2021

把co_download里的 copp::coroutine_context* ctx = copp::this_coroutine::get_coroutine();
改成 copp::coroutine_context::ptr_t ctx{copp::this_coroutine::get_coroutine()}; 就行了
我们这里是侵入式智能指针。这样构造是安全的,就相当于 add_refcount

@owent
Copy link
Owner

owent commented Nov 25, 2021

https://github.com/atframework/atsf4g-co/blob/13f9848563e42a59842177ceb60167d06098c510/src/server_frame/router/router_object_base.cpp#L254

我找了个实际项目中的例子。虽然场景不太一样,但是和你碰到的问题应该是类似的。

@philGemini
Copy link
Author

philGemini commented Nov 25, 2021

我试过的,
编译时候报错:
‘intrusive_ptr_add_ref’ was not declared in this scope intrusive_ptr_add_ref(px);
'intrusive_ptr_release' was not declared in this scope intrusive_ptr_add_ref(px);

我看了代码是 LIBCOPP_UTIL_INTRUSIVE_PTR_REF_FN_DECL 这个定义的宏, 但是我这里没有报错没有
但是没有看到怎么开启 ,
不好意思, 麻烦了

@philGemini
Copy link
Author

我看了
我用的是 copp::coroutine_context_default 这个是有 add_ref 和 release
所以必须是 coroutine_context_default ::ptr_t ctx{(coroutine_context_default *)(copp::this_coroutine::get_coroutine())};
要转为 coroutine_context_default * 就可以了

而且必须在for 里面 确认 detach , 现在是不报错的

void co_downlod()
{
coroutine_context_default ::ptr_t ctx{(coroutine_context_default *)(copp::this_coroutine::get_coroutine())};
....
}

我确认一下, 是否这样内存就不会有问题了, 我看到你时显式调用 ~coroutine_context_default () 了.
但一时的确没有看基类的析构, 向你确认一下

@owent
Copy link
Owner

owent commented Nov 25, 2021

我看了 我用的是 copp::coroutine_context_default 这个是有 add_ref 和 release 所以必须是 coroutine_context_default ::ptr_t ctx{(coroutine_context_default *)(copp::this_coroutine::get_coroutine())}; 要转为 coroutine_context_default * 就可以了

而且必须在for 里面 确认 detach , 现在是不报错的

void co_downlod() { coroutine_context_default ::ptr_t ctx{(coroutine_context_default *)(copp::this_coroutine::get_coroutine())}; .... }

我确认一下, 是否这样内存就不会有问题了, 我看到你时显式调用 ~coroutine_context_default () 了. 但一时的确没有看基类的析构, 向你确认一下

对,这样没有问题。昨天手机码的,sorry没有确认接口。使用你实际使用的coroutine_context_container类型就好了(默认是coroutine_context_default)。

关于detach,这个协程库上层操作暴露的是智能指针,所以是不需要显式detach的。但是如果使用底层的coroutine_context_container接口的话,你得自己保证析构前一定会resume到执行结束,且协程执行结束前不能析构。task和task_manager会自动保证这一点。

@philGemini
Copy link
Author

谢谢啊, 现在安心了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants