c++1114 Multithreading summary

  • 2020-09-28 09:01:57
  • OfStack

Prior to C++11, multithreaded programming in C++ depended on system or third party interface implementation, which affected code portability to a certain extent. In C++11, multithreaded content in boost library is introduced to form C++ standard. After forming the standard, the interface of multithreaded programming part of boost is basically unchanged, which makes it convenient for users who used to develop boost interface to switch to C++ standard interface, and it is easy to upgrade boost interface to C++ standard interface.

We introduce the interface and usage of C++11 multithreading in the following parts.

1. std::thread

std::thread is the thread class of C++11. It is very convenient to use the same method as boost interface. At the same time, C++11's std::thread solves the problem of parameter limitation in boost::thread, which Is due to the variable parameter design style of C++11.

We are familiar with std::thread using style through the following code:


//c11.cpp
#include <iostream>
#include <thread>
void threadfun1()
{
 std::cout << "threadfun1 - 1\r\n" << std::endl;
 std::this_thread::sleep_for(std::chrono::seconds(1));
 std::cout << "threadfun1 - 2" << std::endl;
}
void threadfun2(int iParam, std::string sParam)
{
 std::cout << "threadfun2 - 1" << std::endl;
 std::this_thread::sleep_for(std::chrono::seconds(5));
 std::cout << "threadfun2 - 2" << std::endl;
}
int main()
{
 std::thread t1(threadfun1);
 std::thread t2(threadfun2, 10, "abc");
 t1.join();
 std::cout << "join" << std::endl;
 t2.detach();
 std::cout << "detach" << std::endl;
}

Note: g++ c11.ES38en-ES39en

Operation results:

[

threadfun1 - 1
threadfun2 - 1
threadfun1 - 2
join
detach

]

2. std::atomic

std::atomic is the atomic data type encapsulated by C++11.
What is an atomic data type? Functionally, atomic data types do not compete for data and can be used directly in multiple threads without our users having to add mutex locks to them. From an implementation perspective, we can think of these atomic types as internally locked.

Let us illustrate the characteristics of atomic type std::atomic with a test example.

Using 10 threads, we reduced the variable iCount of type std::atomic from 10 to 1.


//c11.cpp
#include <thread>
#include <atomic>
#include <stdio.h>
#include <iostream>
#include <list>
std::atomic<bool> bIsReady(false);
std::atomic<int> iCount(10);
void threadfun1()
{
 if (!bIsReady) {
  std::this_thread::yield();
 }
 while (iCount > 0)
 {
  printf("iCount:%d\r\n", iCount--);
 }
}
int main()
{
 std::list<std::thread> lstThread;
 for (int i = 0; i < 10; ++i)
 {
  lstThread.push_back(std::thread(threadfun1));
 }
 for (auto& th : lstThread)
 {
  th.join();
 }
}

Operation results:

[

iCount:10
iCount:9
iCount:8
iCount:7
iCount:6
iCount:5
iCount:4
iCount:3
iCount:2
iCount:1

]

As can be seen from the above results, the minimum result of iCount is 1, there is no situation less than or equal to 0, you can change iCount to 100 or even 1000, it may be more intuitive 1.

3. std::condition_variable

std::condition_variable in C++11 USES pthread_cond_wait and pthread_cond_signal1, just like Linux USES pthread_cond_wait and pthread_cond_signal1 to let a thread sleep until it is woken up and then reexecutes. Thread waiting is used so frequently in multithreaded programming that you often have to wait for the return result of a condition that was executed asynchronously.

The code is as follows:


#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
 std::unique_lock<std::mutex> lck(mtx);
 while (!ready) cv.wait(lck); // The thread will go to sleep 
 // ...
 std::cout << "thread " << id << '\n';
}
void go() {
 std::unique_lock<std::mutex> lck(mtx);
 ready = true;
 cv.notify_all();
}
int main()
{
 std::thread threads[10];
 // spawn 10 threads:
 for (int i = 0; i<10; ++i)
  threads[i] = std::thread(print_id, i);
 std::cout << "10 threads ready to race...\n";
 go(); // go!
 for (auto& th : threads) th.join();
 return 0;
}

Operation results:

[

10 threads ready to race...
thread 0
thread 1
thread 2
thread 3
thread 4
thread 5
thread 6
thread 7
thread 8
thread 9

]

In the above code, all 10 threads are dormant before calling the go function, when cv.notify_all() After running, the thread ends its sleep, continues running, and finally outputs the above result.

So that's c++11 & 14- Multithreading knowledge Summary details, more on c++11 & For information on the use of multiple threads, please pay attention to other articles on this site!


Related articles: