7
std::atomic<int> unique_ids;

void foo() {    
  int i = unique_ids.fetch_add(1, std::memory_order_relaxed);
  std::cout<<i;
}

int main(int argc, char* argv[]) {
  std::vector<std::thread> threads;
  for (int i = 0; i < 9; ++i) {
       threads.emplace_back(foo);
  }

  for (int i = 0; i < 9; ++i) {
      threads[i].join();
  }
  std::cout << std::endl;
  return 0;
}

My aim is to use atomic to generate unique id for concurrency program but I do not care about the orders.

For the above code, my understanding is that the output values in foo should be different although their orders are not guaranteed.

I tested the above code hundred times and all the results are what I expected. I am a beginner of atomic / memory order, could anyone help me clarify my understanding?

Thanks in advance. Aimin

P.S. I would like to point out that this question is not the same as the one c++,std::atomic, what is std::memory_order and how to use them since my question is specifically about the understanding of memory_order_relaxed rather than a generic question about the explanation of atomic and memory order.

Community
  • 1
  • 1
Aimin Huang
  • 155
  • 1
  • 6
  • 2
    @πάνταῥεῖ This is about `memory_order_relaxed` not `memory_order`. – nbro Sep 25 '16 at 14:31
  • 3
    @πάνταῥεῖ I think my question is not the same as the one [c++, std::atomic, what is std::memory_order and how to use them](http://stackoverflow.com/questions/9553591/c-stdatomic-what-is-stdmemory-order-and-how-to-use-them) since my question is specifically about the understanding of memory_order_relaxed. Thanks. – Aimin Huang Sep 25 '16 at 14:40
  • @πάνταῥεῖ This is about a specific problem, not some concept in general. The dup closure is incorrect. – 2501 Sep 25 '16 at 17:42
  • @2501 Reopening votes are fine enough. – πάντα ῥεῖ Sep 25 '16 at 17:52
  • @πάνταῥεῖ So you agree that you closed incorrectly? – 2501 Sep 25 '16 at 17:54
  • @2501 I think there's some essential information about `memory_order_relaxed` at the dupe, and just wait how many other users agree or not. – πάντα ῥεῖ Sep 25 '16 at 18:03
  • 1
    @πάνταῥεῖ You really shouldn't abuse your gold powers like that. The usual consensus is to close, not to reopen. Reopening is an option used in rare cases, usually to fix incorrect closures. – 2501 Sep 25 '16 at 18:04
  • 1
    The information at the dupe is fragmented and mostly in comments, which cannot receive downvotes because the dupe didn't squarely ask the question this one asks. The dupe does not really answer whether this particular kind of use case is a legitimate use for relaxed memory ordering, which is what this question clearly asks, IMO. – David Schwartz Sep 26 '16 at 10:36

1 Answers1

2

This is a legitimate use of relaxed memory ordering. You just need the operation to be atomic with respect to other accesses to the very same atomic. Every atomic operation has that characteristic regardless of memory ordering or it wouldn't be atomic at all.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • std::atomic unique_ids; for (int i=0; i<10; ++i) { unique_ids.fetch_add(1, std::memory_order_relaxed); } int ten =unique_ids.load(std::memory_order_release); Base on the understanding, I think the variable ten is guaranteed to be 10, isn't it? – Aimin Huang Sep 26 '16 at 12:36
  • @AiminHuang Assuming `unique_ids` starts out at zero. I don't recall whether it's guaranteed to be set to zero if you don't initialize it. – David Schwartz Sep 26 '16 at 16:17
  • Thanks for your clarification. I will initialize unique_ids in my code. :) – Aimin Huang Sep 27 '16 at 00:32