From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Yubin Ruan <ablacktshirt@gmail.com>
Cc: Akira Yokosawa <akiyks@gmail.com>, perfbook@vger.kernel.org
Subject: Re: synchronize with a non-atomic flag
Date: Fri, 6 Oct 2017 12:12:50 -0700 [thread overview]
Message-ID: <20171006191250.GH3521@linux.vnet.ibm.com> (raw)
In-Reply-To: <CAJYFCiMCnyZnP1kCBAQfpGGd4PBkoMz5ALnkH2K2aqsmwjs+SA@mail.gmail.com>
On Fri, Oct 06, 2017 at 08:35:00PM +0800, Yubin Ruan wrote:
> 2017-10-06 20:03 GMT+08:00 Akira Yokosawa <akiyks@gmail.com>:
> > On 2017/10/06 14:52, Yubin Ruan wrote:
[ . . . ]
> > I/O operations in printf() might make the situation trickier.
>
> printf(3) is claimed to be thread-safe, so I think this issue will not
> concern us.
>
> > In a more realistic case where you do something meaningful in
> > do_something() in both threads:
> >
> > //process 1
> > while(1) {
> > if(READ_ONCE(flag) == 0) {
> > do_something();
> > WRITE_ONCE(flag, 1); // let another process to run
> > } else {
> > continue;
> > }
> > }
> >
> > //process 2
> > while(1) {
> > if(READ_ONCE(flag) == 1) {
> > do_something();
> > WRITE_ONCE(flag, 0); // let another process to run
> > } else {
> > continue;
> > }
> > }
In the Linux kernel, there is control-dependency ordering between
the READ_ONCE(flag) and any stores in either the then-clause or
the else-clause. However, I see no ordering between do_something()
and the WRITE_ONCE().
> > and if do_something() uses some shared variables other than "flag",
> > you need a couple of memory barriers to ensure the ordering of
> > READ_ONCE(), do_something(), and WRITE_ONCE() something like:
> >
> > //process 1
> > while(1) {
> > if(READ_ONCE(flag) == 0) {
> > smp_rmb();
> > do_something();
> > smp_wmb();
> > WRITE_ONCE(flag, 1); // let another process to run
> > } else {
> > continue;
> > }
> > }
> >
> > //process 2
> > while(1) {
> > if(READ_ONCE(flag) == 1) {
> > smp_rmb();
> > do_something();
> > smp_wmb();
> > WRITE_ONCE(flag, 0); // let another process to run
> > } else {
> > continue;
> > }
> > }
Here, the control dependency again orders the READ_ONCE() against later
stores, and the smp_rmb() orders the READ_ONCE() against any later
loads. The smp_wmb() orders do_something()'s writes (but not its reads!)
against the WRITE_ONCE().
> > In Linux kernel memory model, you can use acquire/release APIs instead:
> >
> > //process 1
> > while(1) {
> > if(smp_load_acquire(&flag) == 0) {
> > do_something();
> > smp_store_release(&flag, 1); // let another process to run
> > } else {
> > continue;
> > }
> > }
> >
> > //process 2
> > while(1) {
> > if(smp_load_acquire(&flag) == 1) {
> > do_something();
> > smp_store_release(&flag, 0); // let another process to run
> > } else {
> > continue;
> > }
> > }
This is probably the most straightforward of the above approaches.
That said, if you really want a series of things to execute in a
particular order, why not just put them into the same process?
Thanx, Paul
> Yes it could be tricky when `do_something()' really do something that
> involved other shared variable.
>
> Yubin
>
> > The intention of the code is easier to see when you use well-defined APIs.
> > Just my two cents.
> >
> > Thanks, Akira
> >
> >> That is because:
> >>
> >> 1) on X86/X64, load/store on 32-bits variable are atomic
> >> 2) I use READ_ONCE/WRITE_ONCE to prevent possibly harmful compiler
> >> optimization on `flag'.
> >> 3) I use only one variable to communicate between two processes,
> >> so there is no need for any kind of barrier.
> >>
> >> Does anyone have any objection at that?
> >>
> >> I know using a lock or atomic operation will save me a lot of
> >> argument, but I think those things are unnecessary at this
> >> circumstance, and it matter where performance matter, so I am picky
> >> here...
> >>
> >> Yubin
> >>
> >> [1]: https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong
> >> [2]: https://www.usenix.org/conference/osdi10/ad-hoc-synchronization-considered-harmful
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe perfbook" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at http://vger.kernel.org/majordomo-info.html
> >>
> >
>
next prev parent reply other threads:[~2017-10-06 19:12 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-06 5:52 synchronize with a non-atomic flag Yubin Ruan
2017-10-06 12:03 ` Akira Yokosawa
2017-10-06 12:35 ` Yubin Ruan
2017-10-06 19:12 ` Paul E. McKenney [this message]
2017-10-07 7:04 ` Yubin Ruan
2017-10-07 11:40 ` Akira Yokosawa
2017-10-07 13:43 ` Yubin Ruan
2017-10-07 14:36 ` Akira Yokosawa
2017-10-07 20:20 ` Paul E. McKenney
2017-10-08 9:12 ` Yubin Ruan
2017-10-08 16:07 ` Paul E. McKenney
2017-10-09 8:40 ` Yubin Ruan
2017-10-09 2:14 ` Paul E. McKenney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171006191250.GH3521@linux.vnet.ibm.com \
--to=paulmck@linux.vnet.ibm.com \
--cc=ablacktshirt@gmail.com \
--cc=akiyks@gmail.com \
--cc=perfbook@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox