How to make application flow safe?

I thought thread safety, in particular, meant that it had to satisfy the need for multiple threads to access the same shared data. But it seems that this definition is not enough.

Someone can talk about what needs to be done or take care to make the application flow safe. . If possible, give an answer in C / C ++.

+45
c ++ c multithreading concurrency thread-safety
Feb 26 '11 at 5:22
source share
4 answers

There are several ways to ensure thread safety.

It may be reentrant . This means that the function has no state and does not apply to global or static variables, therefore it can be called from several threads at the same time. The term comes from the fact that one thread can enter a function, while another thread is already inside it.

It may have a critical section . This term is often found around, but to be honest, I prefer critical data . A critical section occurs at any time when your code deals with data that is shared across multiple threads. Therefore, I prefer to focus on this important data.

If you use mutex correctly, you can synchronize access to critical data, protecting against insecure stream modifications. Mutexes and locks are very useful, but with great power comes great responsibility. You must not block the same mutex twice in the same thread (which is self-fading). You must be careful if you acquire more than one mutex, as this increases the risk for a dead end. You must consistently protect your data with mutexes.

If all your functions are thread safe and all your shared data is properly protected, your application should be thread safe.

Like crazy Eddie said, this is a huge question. I recommend reading boost streams and using them accordingly.

Low level caveat : compilers can reorder statements, which can lead to loss of thread safety. With multiple cores, each core has its own cache, and you need to properly synchronize caches to ensure thread safety. Also, even if the compiler does not reorder the statements, the hardware can. Thus, a complete guaranteed thread safety is not possible today. You can get 99.99% of how this happens and work with compiler providers and processor manufacturers to eliminate this lingering clause.

Anyway, if you are looking for a checklist to make the class thread safe:

  • Define any data common to threads (if you skip it, you cannot protect it)
  • create a boost::mutex m_mutex and use it whenever you try to access shared data (ideally, the shared data is private to the class, so you can be more confident that you are protecting it correctly).
  • clear globals. Globals are bad anyway, and good luck trying to do something thread safe with global variables.
  • Beware of the static . This is actually not thread safe. Therefore, if you are trying to make a singleton, this will not work correctly.
  • Beware of the double-check paradigm. Most people who use it are mistaken in some subtle way, and are prone to breakdown due to low levels.

This is an incomplete checklist. I will add more if I think about it, but I hope this is enough to get you started.

+45
Feb 26 '11 at 5:44
source share

Two things:

1. Make sure you are not using global variables. If there are currently global variables, make them members of the stream state structure and pass the structure to the general functions by the stream.

For example, if we start with:

 // Globals int x; int y; // Function that needs to be accessed by multiple threads // currently relies on globals, and hence cannot work with // multiple threads int myFunc() { return x+y; } 

After adding to the state structure, the code becomes:

 typedef struct myState { int x; int y; } myState; // Function that needs to be accessed by multiple threads // now takes state struct int myFunc(struct myState *state) { return (state->x + state->y); } 

Now you may ask why not just pass x and y as parameters. The reason is that this example is a simplification. In real life, your government structure can have 20 fields and skip most of these parameters. 4-5 functions down become complicated. You better pass one parameter instead of many.

2. If your threads have common data that needs to be shared, you need to examine critical sections and semaphores. Each time one of your threads accesses data, it must block other threads and then unlock them when it makes access to shared data.

+11
Feb 26 '11 at 6:43
source share

If you want to make exclusive access to class methods, you must use the lock on these functions.

Different types of locks:

Using atomic_flg_lck:

 class SLock { public: void lock() { while (lck.test_and_set(std::memory_order_acquire)); } void unlock() { lck.clear(std::memory_order_release); } SLock(){ //lck = ATOMIC_FLAG_INIT; lck.clear(); } private: std::atomic_flag lck;// = ATOMIC_FLAG_INIT; }; 

Using atom:

 class SLock { public: void lock() { while (lck.exchange(true)); } void unlock() { lck = true; } SLock(){ //lck = ATOMIC_FLAG_INIT; lck = false; } private: std::atomic<bool> lck; }; 

Using a mutex:

 class SLock { public: void lock() { lck.lock(); } void unlock() { lck.unlock(); } private: std::mutex lck; }; 

Windows only :

 class SLock { public: void lock() { EnterCriticalSection(&g_crit_sec); } void unlock() { LeaveCriticalSection(&g_crit_sec); } SLock(){ InitializeCriticalSectionAndSpinCount(&g_crit_sec, 0x80000400); } private: CRITICAL_SECTION g_crit_sec; }; 

atomic and atomic_flag keep the flow in the number of revolutions. Mutex just sleeps a stream. If the waiting time is too long, it might be better to sleep a stream. The last " CRITICAL_SECTION " holds the thread in the spin count until time is consumed, then the thread goes into sleep mode.

How to use these critical sections?

 unique_ptr<SLock> raiilock(new SLock()); class Smartlock{ public: Smartlock(){ raiilock->lock(); } ~Smartlock(){ raiilock->unlock(); } }; 

Use of the idiom raii. The constructor blocks the critical section and the destructor to unlock it.

Example

 class MyClass { void syncronithedFunction(){ Smartlock lock; //..... } } 

This implementation is thread safe and exclusive because the variable lock is stored on the stack, therefore, when the function area is completed (end of function or exception), the destructor will be called.

I hope you find this helpful.

Thank!!

+3
Mar 09 '16 at 11:16
source share

One idea is to think of your program as a chain of threads switching through queues. Each thread will have one queue, and these queues will be shared (together with a common way to synchronize data (for example, a mutex, etc.)) for all threads.

Then "solve" the producer / consumer problem, however you want the queues not to overflow or overflow. http://en.wikipedia.org/wiki/Producer-consumer_problem

As long as you keep your streams localized, simply exchange data by sending copies in turn and do not access the stream of unsafe things, such as (most) gui libraries and static variables in several streams, then you should be fine.

0
Feb 26 '11 at 5:57
source share



All Articles