这几天在学习leveldb相关的实现,网上的资料挺多的,在分析代码过程中,也参考了一些别的分析文章,这块会在后续总结下这段时间的学习和思考。
但昨天又回顾了下当时分析的协程实现文章和源码,有些技术点没仔细分析或者不是很明白,今天就总结下。
关于phxrpc中有处理后响应数据push到dataflow中
有如下代码:
100 void EpollNotifier::Notify() {
101 ssize_t write_len = write(pipe_fds_[1], (void *)"a", 1);
102 if (write_len < 0) {
104 }
105 }
213 void UThreadEpollScheduler::NotifyEpoll() {
214 if (epoll_wait_events_per_second_ < 2000) {
216 epoll_wake_up_.Notify();
217 }
218 }
443 void Worker::WorkerLogic(void *args, HttpRequest *request, int queue_wait_time_ms) {
463 pool_->scheduler_->NotifyEpoll();
466 }
在工作线程中,当有数据push到dataflow后,调用线程池的NotifyEpoll
,然后这里可能会有多个工作线程执行,里面并没有去做临界区工作。在这个实现中,写pipe,只是作为通知,哪怕write不是原子的,最后数据怎么样并不重要,并不使用。然后查了下write是否是原子的,作如下分析引用:
“对于write(pipefd,buf,nbyte),其要点如下:
如果nbyte<=PIPE_BUF,不管O_NONBLOCK是否设置,其写操作都是原子的,就是说多个进(线)程都在此条件下同时写同一个管道不会引起数据交错。
如果nbyte>PIPE_BUF,是不能保证写操作是原子的,写入的数据可能与其他进程写入的数据交错。”
总结,对于socket这种,一般socket fd交由一个线程负责读写,不会跨线程,不然出现数据包交错等,write文件的话,目前只经历过日志这种,专门由日志线程负责。
关于O_APPEND模式write的原子性
Linux命令之write调用的原子性
write man page
《Linux 多线程服务端编程》
关于libco中的一些额外思考总结
当时分析确实没有想过为什么要这么写,可能是自己没有实际使用经验,纯粹分析技术点,并没有把所有的坑都考虑到。
libco不像上面或pebble的协程,这里如果使用共享栈,在栈上引用的局部地址/引用,或者变量值,在让出cpu时,拷贝到一个由malloc申请的空间,如果内容原样拷贝回去是不会出现问题的,私有栈也是。这点确实没有像今天这样认真想过。
还有如果要协程间相互协作,涉及到锁之类的,那线程锁肯定不行吧,是否有协程间的锁呢?或者类似条件变量的,都需要考虑。
另外还有个,工作线程和IO线程间的通信,有数据push到dataflow时,可能会不停的notify,这块不知是否有优化的地方?比如如果容忍一点误差的话,可以不用加锁的判断queue是否有数据,没有的话则notify等。
网友评论