GRPC淺析-completion_queue
GRPC淺析-completion_queue
上一節傳送門
前言
completion_queue(以下簡稱cq)有三中型別,分別是GRPC_CQ_NEXT,GRPC_CQ_PLUCK和GRPC_CQ_CALLBACK。
cq_vtable
/*cq的操作介面如下*/
struct cq_vtable {
grpc_cq_completion_type cq_completion_type;
size_t data_size;
void (*init)(void* data,
grpc_experimental_completion_queue_functor* shutdown_callback);
void (*shutdown)(grpc_completion_queue* cq);
void (*destroy)(void* data);
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage, bool internal);
grpc_event (*next)(grpc_completion_queue* cq, gpr_timespec deadline,
void* reserved);
grpc_event (*pluck)(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline, void* reserved);
};
為cq分配記憶體時,會分配額外的cq_vtable::data_size + cq_poller_vtable::size()的記憶體,用於cq_data和poller。poller也就是上一節中提到的pollset。
cq_data有3種,分別是cq_next_data,cq_pluck_data和cq_callback_data,與3種型別的cq分別對應。
cq_next_data內部維護一個完成事件佇列(佇列的push基於CSA,pop基於Spinlock+CSA),work介面會從佇列中消費完成事件。
cq_pluck_data內部維護一個完成事件連結串列,與cq_next_data不同的是,事件不一定是按照FIFO來消費的。並且維護了一個pluckers,當執行緒即將進入(也許會)阻塞情況時,將執行緒對應的woker和tag新增到pluckers裡,當有這個tag型別完成事件時,喚醒執行緒消費完成事件。
cq_callback_data沒有維護完成事件的資料結構。
接下來描述cq_vtable 裡的介面。
init——在初始化cq_data,引數shutdown_callback只有callback型別的cq才使用到。
shutdown——關閉一個cq。callback型別的cq會呼叫init時傳入的shutdown_callback。
destroy——呼叫cq_data解構函式。
begin_op——開始一個完成操作。
end_op——產生一次完成事件。不同的cq,end_op有不同的行為。
- 對於next型別cq。
將完成事件新增到cq_data的佇列裡。如果新增到佇列裡的事件是佇列首個元素,則kick一次worker,這保證執行緒呼叫cq_next時不會處於有完成事件卻阻塞起來的情況。 - 對於pluck型別cq。
將tag完成事件新增到連結串列裡,如果pluckers有此tag對應的worker,則kick此woker。 - 對於callback型別cq。
直接消費完成事件,並排程一個callback。
next——只有next型別cq實現此介面。如果有完成事件,則消費返回。否則,進入pollset_work等待I/O事件。
pluck——只有pluck型別cq實現此介面。如果存在對應tag完成事件,則消費返回,否則等待對應的tag完成事件發生。
cq_poller_vtable
/*poller相關操作也就是上一節所說的pollset*/
struct cq_poller_vtable {
bool can_get_pollset;
bool can_listen;
size_t (*size)(void);
void (*init)(grpc_pollset* pollset, gpr_mu** mu);
grpc_error* (*kick)(grpc_pollset* pollset,
grpc_pollset_worker* specific_worker);
grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
grpc_millis deadline);
void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
void (*destroy)(grpc_pollset* pollset);
};
有3種型別的poller,分別是GRPC_CQ_DEFAULT_POLLING,GRPC_CQ_NON_LISTENING和GRPC_CQ_NON_POLLING。第一種型別poller可以監聽所有fd,有正常pollset的操作,而第二種出了listening fd不可監聽外,介面行為與第一種完全一樣。第三種,與pollset沒有關聯,也就沒有等待I/O事件的行為。
相關文章
- iOS Block淺淺析iOSBloC
- 淺析 JWTJWT
- MongoDB淺析MongoDB
- RunLoop 淺析OOP
- Nginx淺析Nginx
- 淺析 requestAnimationFramerequestAnimationFrame
- 淺析PromisePromise
- 淺析GitGit
- 淺析RedisRedis
- Jvm 淺析JVM
- Webpack 原理淺析Web
- css: clip淺析CSS
- 淺析Promise原理Promise
- BTrace 原理淺析
- 淺析Java NIOJava
- 字串模板淺析字串
- 淺析 ReentrantLockReentrantLock
- HTTP Cache 淺析HTTP
- 淺析JAVA反射Java反射
- setXfermode 模式淺析模式
- AQS原理淺析AQS
- koa原理淺析
- CGLib淺析CGLib
- 淺析DES原理
- ejs 淺析JS
- AIDL淺析AI
- Fragment流程淺析Fragment
- 淺析SELinuxLinux
- IOS代理淺析iOS
- MySQL Replication淺析MySql
- web安全淺析Web
- Seata原理淺析
- InheritedWidget原理淺析
- 淺析微服務框架微服務框架
- 淺析JavaScript非同步JavaScript非同步
- canvas.drawText淺析Canvas
- Java快取淺析Java快取
- markdown-it 原理淺析