-1
std::deque<T> dq;
Thread_function(pointer to queue as argument)     // created 8 threads
{
     vertext_found = true;
     **v is initialized to NULL
     while ( i < dq->size())
     {
          EnterCriticalSection(&h);
          if( i < dq.size() ) {
              v = dq.at(i);      // accessing element of queue without popping
              i++;
              vertext_found = true;
          }
          LeaveCriticalSection(&h);
          if (vertext_found && (i < dq.size()) && v != NULL)
          {
              **operation on 'v'
              vertext_found = false;
          }
     }
}

Will this be a data race condition especially when processing "while ( i < dq->size())" outside the Critical Section? Is my approach correct? Otherwise plz suggest me.

Sumanth
  • 595
  • 3
  • 14
  • 39
  • Is `std::deque dq;` really meant to be a local object? I see you are accessing it as if it was a pointer (`dq->size()`) – Andy Prowl Mar 10 '13 at 17:50
  • It looks like you are only ever reading from the queue. Is that correct? – usr Mar 10 '13 at 17:52
  • 5
    Post a more complete example. You are leaving out too much information. Your dq appears to be thread local but your question implies it isn't. – Brandon Mar 10 '13 at 17:57
  • If dq is shared between threads then please explain whether you modify it in parallel with accessing or not. If you have 8 threads that only reading the queue without modifications, then you don't need sync at all.. – nogard Mar 10 '13 at 17:59
  • i am just reading the queue.. but need to access each element by different thread.. yes i am passing pointer to queue – Sumanth Mar 10 '13 at 19:28

1 Answers1

4

Will this be a non-interference in a multi-threaded environment?

In your question's text, dq (like all the other variables in your function) is a local object:

std::deque<T> dq;

If this is really the case, then the question has an easy answer: "Yes". It is thread-safe because there is no contention: each thread works on a local object, and since there is no sharing, there can't be any data race.


Now assuming that your code intended to show the use of a shared data structure, and that dq is actually a global object or something somehow accessible by several threads simultaneously (this is what the dq->size() function call seems to suggest), then the answer is "It depends".

If all of your threads are concurrently executing only the function you are showing, and dq is a reference or pointer to const, so that your function doesn't contain any call to any non-const member functions, then the answer is "Yes, but you don't really need any critical section at all in this case". Paragraph 17. 6.5.9/3 of the C++11 Standard specifies:

A C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.

The reference to Paragraph 1.10 (and in particular to 1.10/21), which defines what a data races is, makes the meaning of the above Paragraph clearer:

The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior. [...]

Finally, Paragraph 1.10/4 specifies when two actions are conflicting:

Two expression evaluations conflict if one of them modifies a memory location (1.7) and the other one accesses or modifies the same memory location.

What follows from all this is that const member functions are necessarily thread-safe. You may be interested in watching this presentation by Herb Sutter about it.

Since deque<T>::size() is a const member function, and at() is a const member function (because you are calling it from a reference or pointer to const) which returns a reference to const, there is no need to synchronize access from multiple threads.


If your dq is not a reference or pointer to const, then the answer is "No", because at() is a non-const member function. Moreover, since v is a non-const reference to an element, your "operation on v" could be non-const, therefore introducing a data-race on the elements of dq rather than on dq itself.

Similarly, if your threads are concurrently accessing and modifying dq through other functions, then the answer is again "No", because you are not protecting all the accesses to the shared object. Read operations conflict with write operations (see above), and you are only protecting some of them. In this case, your critical section should span the entire while cycle.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • @Andy.. edited my original post.. I am not modifying(deleting or writing) the queue. I am just accessing/reading elements of queue. But no two threads should access the same element of the queue. Sometimes the program executes fine but sometimes getting "access violation reading location error" at "**operation on 'v'". What might be the problem? – Sumanth Mar 11 '13 at 01:40
  • @Hello: Are you just accessing those elements? Or are you modifying them? If you are just accessing them, then all the `const` functions should be thread-safe, which means you can let `dq` be a reference or pointer to `const`. In that case, you need no critical section at all. If you are modifying those elements, then the critical section should wrap the "operation on v" as well. Notice, that since you are never modifying the queue, the redundant `if (i < dq.size())` is useless. – Andy Prowl Mar 11 '13 at 10:48