banner



How To Share Data Between Two Threads In C++

Contents [Show]

    • CP.20: Employ RAII, never plain lock()/unlock()
    • CP.21: Utilise std::lock() or std::scoped_lock to larn multiple mutexes
    • CP.22: Never call unknown lawmaking while holding a lock (due east.g., a callback)
    • What'south next?

If you want to take fun with threads, you should share mutable data between them. In society to get no data race and, therefore, undefined behavior, you lot have to think about the synchronization of your threads.

retriever

The three rules in this post are maybe quite obvious for the experienced multithreading developer but very crucial for the novice in the multithreading domain. Here are they:

  • CP.20: Use RAII, never plain lock()/unlock()
  • CP.21: Use std::lock() or std::scoped_lock to acquire multiple mutexes
  • CP.22: Never call unknown code while holding a lock (e.g., a callback)

 Let's commencement with the most obvious dominion.

CP.twenty: Use RAII, never plain lock()/unlock()

No naked mutex! Put your mutex always in a lock. The lock will automatically release (unlock) the mutex if it goes out of scope. RAII stands for Resource Acquisition Is Initialization and means that you bind the lifetime of a resource to the lifetime of a local variable. C++ automatically manages the lifetime of locals.

std::lock_guard, std::unique_lock, std::shared_lock (C++14), or std::std::scoped_lock (C++17) implement this pattern simply as well the smart pointers std::unique_ptr, and std::shared_ptr. My previous post Garbage Collection - No Thank you  explains the details to RAII.

What does this mean for your multithreading code?

std::mutex mtx;            void            do_stuff() {     mtx.lock();            // ... do stuff ... (one)            mtx.unlock(); }          

It doesn't affair if an exception occurs in (1) or yous merely forgot to unlock the mtx; in both cases, y'all will get a deadlock if some other thread wants to learn (lock) the std::mutex mtx. The rescue is quite obvious.

std::mutex mtx;            void            do_stuff() {     std::lock_guard<std::mutex>            lck {mtx};            // ... do stuff ...            }            // (1)          

Put the mutex into a lock and the mutex volition automatically be unlocked at (1) considering the lck goes out of telescopic.

CP.21: Use std::lock() or std::scoped_lock to larn multiple mutexes

If a thread needs more than one mutex, you have to be extremely careful that you lock the mutexes e'er in the same sequence. If not, a bad interleaving of threads may cause a deadlock. The following program causes a deadlock.

            // lockGuardDeadlock.cpp            #include <iostream>            #include <chrono>            #include <mutex>            #include <thread>            struct            CriticalData{   std::mutex mut; };            void            deadLock(CriticalData&            a, CriticalData&            b){    std::lock_guard<std::mutex>guard1(a.mut);            // (2)                        std::cout            <<            "Thread: "            <<            std::this_thread::get_id()            <<            std::endl;    std::this_thread::sleep_for(std::chrono::milliseconds(1));     std::lock_guard<std::mutex>guard2(b.mut);            // (2)            std::cout            <<            "Thread: "            <<            std::this_thread::get_id()            <<            std::endl;            // do something with a and b (critical region)        (3)            }            int            main(){    std::cout            <<            std::endl;    CriticalData c1;   CriticalData c2;    std::            thread            t1([&]{deadLock(c1, c2);});            // (one)            std::            thread            t2([&]{deadLock(c2, c1);});            // (1)            t1.join();   t2.join();    std::cout            <<            std::endl;  }          

Thread t1 and t2 need 2 resources CriticalData to perform their chore (3). CriticalData has its ain mutex mut to synchronize the access. Unfortunately, both invoke the function deadlock with the arguments c1 and c2 in a unlike sequence (one). Now we have a race condition. If thread t1 tin can lock the first mutex a.mut but non the 2nd one b.mut because in the meantime thread t2 locks the second one, we volition go a deadlock (2).

lockGuardDeadlock

The easiest style to solve the deadlock is to lock both mutexes atomically.

With C++11, yous tin utilize an std::unique_lock together with std::lock. std::unique_lock yous can defer the locking of its mutex. The function std::lock, which tin can lock an arbitrary number of mutexes in an atomic way, does the locking finally.

            void            deadLock(CriticalData&            a, CriticalData&            b){     std::unique_lock<mutex>            guard1(a.mut, std::defer_lock);     std::unique_lock<mutex>            guard2(b.mut, std::defer_lock);     std::lock(guard1, guard2);            // do something with a and b (critical region)            }          

With C++17, a std::scoped_lock can lock an arbitrary number of mutex in one atomic operation.

            void            deadLock(CriticalData&            a, CriticalData&            b){     std::scoped_lock(a.mut, b.mut);            // do something with a and b (critical region            }          

CP.22: Never telephone call unknown code while holding a lock (e.g., a callback)

Why is this code snippet actually bad?

            
std::mutex chiliad;
{ std::lock_guard<std::mutex> lockGuard(m); sharedVariable = unknownFunction(); }

I can only speculate about the unknownFunction. If unknownFunction

  • tries to lock the mutex chiliad, that will be undefined behavior. Most of the time, you will get a deadlock.
  • starts a new thread that tries to lock the mutex yard, you will go a deadlock.
  • locks some other mutex m2 you may get a deadlock because you lock the 2 mutexes yard and m2 at the aforementioned time. Now information technology can happen that another thread locks the same mutexes in a dissimilar sequence.
  • will non directly or indirectly try to lock the mutex m; all seems to exist fine. "Seems" because your coworker can modify the office or the role is dynamically linked, and y'all get a different version. All bets are open to what may happen.
  • work as expected you may have a functioning trouble because you lot don't know how long the function unknownFunction would take. What is meant to exist a multithreaded programme may become a single-threaded program.

To solve these issues, use a local variable:

std::mutex thousand;
machine tempVar = unknownFunction(); { std::lock_guard<std::mutex> lockGuard(m); sharedVariable = tempVar; }

This additional indirection solves all issues. tempVar is a local variable and tin, therefore, not be a victim of a data race. This means that you can invoke unknownFunction without a synchronization mechanism. Additionally, the time for belongings a lock is reduced to its bare minimum: assigning the value of tempVar to sharedVariable.

What'south side by side?

If you don't call join or detach on your created thread child, the child volition throw a std::cease exception in its destructor. std::stop calls per default std::abort. To overcome this consequence, the guidelines back up library has a gsl::joining_thread which calls join at the cease of its scope. I volition accept a closer look at gsl::joining_thread in my next mail.

Thanks a lot to my Patreon Supporters : Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm , Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Red Trip, Alessandro Pezzato , Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, Eduardo Velasquez, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Ralf Holly, and Juan Dent.

Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, Ralf Abramowitsch, John Nebel, and Mipko.

My special cheers to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

My special cheers to PVS-Studio PVC Logo

Mentoring Program

My new mentoring programme "Fundamentals for C++ Professionals" starts on the 22nd of April. Go more than information here: https://bit.ly/MentoringProgramModernesCpp.

Seminars

I'g happy to give online seminars or confront-to-face seminars worldwide. Delight call me if you accept any questions.

Bookable (Online)

German

  • Embedded Programmierung mit modernem C++: 28.06.2022 - 30.06.2022 (Termingarantie)
  • C++20: 23.08.2022 - 25.08.2022 (Termingarantie)
  • Clean Lawmaking: Best Practices für modernes C++: 11.x.2022 - thirteen.10.2022
  • Design Pattern und Architekturpattern mit C++: 08.11.2022 - ten.11.2022 (Termingarantie)

Standard Seminars (English language/German)

Here is a compilation of my standard seminars. These seminars are only meant to give y'all a start orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Blueprint Blueprint and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

  • Phone: +49 7472 917441
  • Mobil:: +49 176 5506 5086
  • Mail: This email address is being protected from spambots. Y'all need JavaScript enabled to view information technology.
  • German language Seminar Folio: www.ModernesCpp.de
  • English Seminar Page: world wide web.ModernesCpp.net

Modernes C++,

RainerGrimmSmall

How To Share Data Between Two Threads In C++,

Source: https://www.modernescpp.com/index.php/c-core-guidelines-sharing-data-between-threads

Posted by: cokleyunfortuabood.blogspot.com

0 Response to "How To Share Data Between Two Threads In C++"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel