Is this a race condition?

↘锁芯ラ 提交于 2019-12-05 03:44:25

I think whether the example algorithm has a race condition depends on the what the algorithm is expected to do.

There is no data race on the modification of i - those accesses are serialized and occur atomically with respect to each other.

However, if it's important to the correctness of the algorithm that the increment occur before the multiplication (or vice versa), then there is a race and other means would have to be used to synchronize the execution of the algorithm. If the algorithm is supposed to be a complicated way to calculate i * 2 + 1 (as ridiculous as it might be to perform the calculation using threads), then there's a race condition.

Consider the following program snippet:

int data;

pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;

void* wait_for_data(void*)
{
    pthread_mutex_lock( &mux);
    pthread_cond_wait( &condvar, &mux);

    puts("got the data: %d\n", data);

    pthread_mutex_unlock( &mux);

    return 0;
}


void* set_data(void*)
{
    pthread_mutex_lock( &mux);

    data = 42;

    pthread_cond_signal( &condvar);

    pthread_mutex_unlock( &mux);

    return 0;
}

Both threads are essentially completely mutually exclusive - there is no data race. However, if set_data() signals the condition variable before wait_for_data() gets around to waiting on it, wait_for_data() will never complete. I think most people would call that a race condition due to improper use of the condition variable.

No it's not. Because it locks before reading and writing to i. So the reads and writes in your example are always consistent. Of course you should unlock after each operation, but I guess you just forgot to add that in your pseudo-code.

No, this is one of the expected sequences of execution. A race would be not protecting the counter with some sort of a lock, thus allowing for load-modify-store cycles to run concurrently.

Edit 0:

@Gheorghe, think about an example of a joint bank account and two people taking their money out of it at difference bank offices at the same time. A clerk at each location would need to check account balance, give out cash, and write down new balance. If this is not "atomic" with regard to the balance, i.e. the account is not "locked" during this operation, they might end up getting more money between two of them then they had in the bank. Banks don't like that.

But if the account is locked while being manipulated, does the output depend on the timing? Yes, absolutely - total sum doesn't change, but the split between two of them can be different.

What matters is the consistency of the protected value - no matter in what sequence and how many times these two guys take money from the back, they don't get more then they originally had.

assylias

Note: I give an answer from a Java perspective as the question originated from a previous discussion about the Java Memory Model.

There seems to be a lot of confusion around the definition of "race condition", which is why you are getting different answers.

If you mean "data race", there is only one valid definition in the context of Java, and it is given by the Java Language Specification 17.4.5:

When a program contains two conflicting accesses (§17.4.1) that are not ordered by a happens-before relationship, it is said to contain a data race.

Conflicting accesses is defined in 17.4.1:

Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.

In your case, your code contains a happens-before relationship as defined by 17.4.5:

An unlock on a monitor happens-before every subsequent lock on that monitor.

So there is no data race in your code in a Java context - anyone saying otherwise is using a non-Java definition.

Others have commented about a "general race" in the sense that any of the 2 codes could run first, but that's an algorithm question: either your code is parallelizable and it should not matter, or it is not and you should run it sequentially. But that's a bug, not a data race.

yes. by definition it is. Also you will have a problem with variable volatility. In this case there is no guarantee which thread loads the variable from memory to which register and then saves it to memory. So it might be that in some cases,one thread will get a stale value. In many languages you will have to somehow make sure that you will always fetch a clean copy. (in java volatile)

http://www.freebsd.org/doc/en/books/developers-handbook/secure-race-conditions.html

I think that is a good definition also.

Reading: http://dl.acm.org/citation.cfm?id=130623

"Two different notions have been implicitly considered: one pertaining to programs intended to be deterministic (which we call general races) and the other to nondeterministic programs containing critical sections (which we call data races)."

so I would say that it is a "general race" if you assumed that program to always produce the same result. If not, you just have very weird design.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!