0

problem: Two threads which are doing bitwise operation(clearing two different bit positions) on same unsigned int variable is creating a race condition. (Its a flag variable).

Currently trying solution: use mutex, each time before setting or clearing the bit position.

Environment:Android userspace, bionic, C++

Now, I also think of checking whether, i can avoid the race condition with android's atomic operation functions, android_atomic_and/android_atomic_or and defining the variable as volatile unsigned int. This is logically similar to kernel space atomic operations like atomic_set, atomic_and as per my understanding.

So, if somebody can clear my doubt or if other solution to fix this issue better way, please help.

Balamurugan A
  • 1,886
  • 2
  • 17
  • 19
  • `volatile` **does not** imply atomicity. Other than that it seems like you have some thoughts towards a solution, though you might consider if you could simply separate the two flags to their own variables/memory words. – Chris Stratton Apr 29 '14 at 15:24
  • @ChrisStratton, each bit in that variable represents one flag, so that variable, say mFlags, will contain upto 32 flag condition, and threads will be accessing the same mFlag variable to set and clear corresponding bit positions to update the status. – Balamurugan A Apr 29 '14 at 15:34
  • 2
    Given you have multiple threads, bitmapping these flags is probably a bad design decision, unless you are willing to protect them with a mutex or some sort of homegrown synchronized setter. It could be a lot simpler to just split them into 32 word-sized variables. – Chris Stratton Apr 29 '14 at 15:38
  • std::atomic http://en.cppreference.com/w/cpp/atomic/atomic – Paolo Brandoli Apr 29 '14 at 15:42
  • What @ChrisStratton says - don't use bit flags. – Martin James Apr 29 '14 at 16:03
  • I had seen in many places of Android AOSP code, bit flags are used. eg. AudioFlinger Service code, which is very common to be accessed from multiple threds across the system. please refer, https://android.googlesource.com/platform/frameworks/av/+/android-4.1.1_r5/media/libmedia/AudioTrack.cpp – Balamurugan A Apr 30 '14 at 07:37
  • Even without threading, bitwise operations will slow most systems these days, in fact higer languages will allocate 64 bits for a byte object because of this. Although they seem elegant, unless you are storing a LOT of really small values then I'd give each it's own memory location. If you are storing, say thousands of boolean values then you may want to write a system around your data (encapsulate it) to serialize reads and updates while clearly defining access to the data. – Bill K May 01 '14 at 21:29
  • 1
    `android_atomic_and`/`android_atomic_or` should do what you want. You don't have to declare your `int` variable as volatile to use those functions. But to read the variable's value you'll probably want to use something like `android_atomic_release_load()`. – Michael Burr May 01 '14 at 21:50

1 Answers1

2

There are, as always many different solutions to this problem. Basic integer operations are usually atomic on most systems. But you have to make sure, the variable is not cached, and that the basic operation can be done in one step. So setting the integer to 0 would be such a basic operation. But increasing it's value by one, or change one bit somewhere isn't. Cause there you are reading the current state, calculating the new one, and finally writing it back. Another thread doing the same thing simultaneously would lead to an inconsistent state. (as an example a variable that was increased twice, but it's value is only one more)

One solution would be to surround access to this integer with locks.

Another and faster approach would be to use a compare_and_set method for writing. (reading should be no problem) In this case, make sure your variable is not cached in one of the CPUs, as an example by declaring it volatile. This could be helpful for you;

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...) type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...) These builtins perform an atomic compare and swap. That is, if the current value of *ptr is oldval, then write newval into *ptr. The “bool” version returns true if the comparison is successful and newval was written. The “val” version returns the contents of *ptr before the operation.

I have this part from here: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

Using compare and set correctly, you can make sure the variable is only modified, if nobody else is doing it at the same time. Therefore you need to use it inside a while loop as shown in this thread here: How to compare and swap atomically in ARM7?

A third approach would be to head for a library which provides you a long list of many different "Atomic-Operations". This might be the cleanest way. Doing the handling yourself using volatile and compare-and-set might be dangerous, as it won't warn you or others if the special treatment of the variable was forgotten somewhere.

one last thing. Please be informed, that the unprotected read access only works with a single integer variable. If you are working with a double, or with two integers, you might get an inconsistent state. Where during a write of process 0, half of the double variable (or one integer of two) already has the new value and the other part still the old value while you read it in thread 1. This would directly lead to a hard to find bug. Rarely happening, but disaster when it does. (This part applies only to common 32bit CPU systems. Certain smaller systems might handle memory in smaller chunks. 64bit systems on the other hand, usually handle two integers (64bit) as one chunk, there it would work with the double, but not with bigger constructs)

good luck!

Community
  • 1
  • 1
user3387542
  • 611
  • 1
  • 8
  • 28