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

Data race in AsyncLogging #288

Closed
ColdOrange opened this issue Aug 19, 2017 · 10 comments
Closed

Data race in AsyncLogging #288

ColdOrange opened this issue Aug 19, 2017 · 10 comments

Comments

@ColdOrange
Copy link

陈老师你好,最近在学习 AsyncLogging 部分的时候,发现一个可能的潜在 data race 问题:
在 threadFunc 中 while (running_) 与 stop 中的 running_ = false 语句可能会存在对 running_ 访问的 data race,改成 atomic<bool> 应该可以解决这个问题。
当然如果程序永远在循环中不退出的话是不会有问题的,不知道这个地方是否有必要修改一下?

@chenshuo
Copy link
Owner

严格地说,是有 data race。改成 atomic 是对的,C++ 98 也可以用 GCC Atomic Builtins。EventLoop::quit_ 同理。

@ColdOrange
Copy link
Author

但是这里的 data race 不会影响程序的正确性,所以在考虑性能的情况下是可以接受的,可以这样理解吗?

@chenshuo
Copy link
Owner

如果严格按照 C++ 标准来说,会影响正确性。不过在 X86 Linux 下用 GCC / clang 编译出来的程序到目前为止还没有出错。
另外,这么写不是为了考虑性能,比起别的正常开销来说,读一个 bool 变量的成本可以忽略不计。

@ColdOrange
Copy link
Author

不好意思可能是我没表达清楚,我的意思是说是否考虑到 atomic 或者 mutex(EventLoop::quit_ 的情况只用 atomic 好像还是不能保证线程安全)的开销,所以才没有做出修改?
另外,对于 EventLoop.cc 107 行处的这个 FIXME,是不是可以用一个 CountDownLatch 解决呢?

@chenshuo
Copy link
Owner

chenshuo commented Aug 23, 2017

是否考虑到 atomic 或者 mutex的开销,所以才没有做出修改?

No.

对于 EventLoop.cc 107 行处的这个 FIXME,是不是可以用一个 CountDownLatch 解决呢?

How ?

@ColdOrange
Copy link
Author

第一点看到您已经修复了;第二点我是这样想的:
在 EventLoop 类中加一个 CountDownLatch 成员变量,初始化值为 1。在 EventLoop::loop() 第 108 行之后调用 latch_.countDown() 。在 EventLoop::quit() 最开始调用 latch_.wait() 。这样是不是可以解决 quit() 在 loop() 之前调用时产生的竞争问题呢?

@chenshuo
Copy link
Owner

如果同一个线程依次调用 quit() 和 loop(),会死锁。

@ColdOrange
Copy link
Author

对的,是我之前考虑不周了。我又想了一下,其实 quit() 的设计初衷之一应该是支持 quit() 之后再调用 loop() 的吧(否则在 loop() 中也就不必加 108 这一行了)。在这种情况下我能想到的最好的解决方案就是忽略在 loop() 开始之前的 quit() 调用,也就是现在这种处理方法了。
我没有其他问题了,谢谢您的耐心回复。

@chenshuo
Copy link
Owner

108 这一行原本是为了支持 loop() -> quit() -> 再次 loop()。不过好像没有人这么用。
如果一定要支持 quit() -> loop(),可以把 quit_ 改成 enum { INIT, QUIT, LOOP }, 然后 loop() 里用 compare_and_swap 来判断是否用户已经调用过 quit()。

@ColdOrange
Copy link
Author

是的。不过我觉得这样会有一些语义上的问题吧,比如在 loop1 -> quit1 -> quit2 -> loop2 这个过程中,我认为没有办法分清 quit2 的调用意图是结束 loop1 还是结束 loop2,所以我觉得在两次 loop 之间(一次结束之后另一次开始之前,以及第一次 loop 开始之前)的 quit 直接忽略掉比较好一点。这一点您怎么想呢?

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

No branches or pull requests

2 participants