C ++ implementation issues and visibility issues - what's the general engineering practice?

From my research, I know the concepts of hunger, deadlock, fairness and other concurrency issues. However, theory differs from practice to some extent, and real engineering problems often involve more granularity than academic blah blah ...

As a C ++ developer, I've been worried about threading issues for a while ...

Suppose you have a shared variable x

that refers to some larger portion of the program's memory. The variable is shared between the two threads A

and B

.

Now, if we are considering read / write operations x

from streams A

and B

, perhaps, at the same time, it is necessary to synchronize these operations, right? Thus, accessing x

requires some form of synchronization, which can be achieved using mutexes, for example.

Now consider another scenario where it is x

initially written as a stream A

, then piped to a stream B

(somehow) and that stream only reads x

. The thread then B

issues a response to the x

called y

and feeds it back to the thread A

(again, somehow). My question is what synchronization primitives should I use to make this scenario thread safe. I've read about atomatics and more importantly, memory worries - are these tools I should rely on?

This is not a typical "critical section" scenario. Instead, some data is transferred between threads without the ability to write concurrently to the same memory location. Thus, after writing, the data must first be "reddened" so that other threads could see it in a correct and consistent state before reading it. What is it called in the literature, is it "visibility"?

How about pthread_once

and its Boost / std counterpart, i.e. call_once

... Does it help if both tags are passed between threads x

, and y

through some sort of "message queue" that is accessed using a "once" function. AFAIK this serves as a kind of memory barrage, but I couldn't find confirmation for this.

How about CPU caching and consistency? What should I know about this from a technical point of view? Does this kind of knowledge help in the above scenario or any other scenario commonly found in C ++ development?

I know that I could mix many topics, but I would like to better understand what general engineering practice is so that I can reuse already known patterns.

This question is primarily related to the C ++ 03 situation, as this is my day-to-day environment at work. Since my project mainly includes Linux, I can only use pthreads and Boost, including Boost.Atomic. But I'm also wondering if anything about such questions has changed since the advent of C ++ 11.

I know the question is abstract and not precise, but any input could be helpful.

+3


source to share


1 answer


you have a shared variable x

That you were wrong. Threading is much easier if you transfer ownership of the work items using some kind of consumer-producer threading network, and from the point of view of the rest of the program, including all the business logic, nothing is shared.

Passing messages also helps prevent cache collisions (because a true exchange doesn't exist), except for the producer and consumer queue itself, and this has a trivial performance impact if the unit of work is large - and organizing the data in messages will help reduce false usage).



Parallelism scales best when you divide the problem into sub-tasks. Small subproblems are also much easier to reason about.

It looks like you are already pondering these lines, but no, thread primitives like atomistics, mutexes and fences are not very good for messaging applications. Find a real implementation of the queue (queue, circular ring, Disruptor, they go under different names, but all meet the same need). The primitives will be used internally by the queue implementation, but will never be used by application code.

+10


source







All Articles