545-C + + multithreaded programming

C + + language level multi-threaded programming code can cross platform windows/linux/mac

Introduction to C + + multithreading

thread(Thread class)
mutex(mutex )
condition_variable(Communication between threads, condition variables)

Smart lock:
lock_quard
unique_lock

atomic Atomic type based on CAS The atomic type of the operation is thread safe

sleep_for(sleep) 
C++Language level thread(The bottom layer uses the method of the following platform) 
   windows        linux  strace ./a.out(Program initiated trace print command)
      |             |
createThread    pthread_create

The compiler can compile and add a macro to identify the current operating system to adapt. The bottom layer of thread can automatically call the corresponding functions through language level. The bottom layer still calls the API created by the system, but the language level is encapsulated to make it easier for users to use.

Multithreaded programming

Thread content:
1, How to create and start a thread
std::thread defines a thread object and passes in the thread functions and parameters required by the thread,
Thread auto start

2, How does a child thread end
When the sub thread function runs, the thread ends

3, How does the main thread handle child threads
t.join(): wait for the T thread to end, and the current thread will continue running
t.detach(): set the T thread as a separate thread, the main thread ends, the whole process ends, and all sub threads end automatically!

Code example:

#include <iostream>
#include <thread>
using namespace std;

void threadHandle1(int time)
{
	//Let the child thread sleep for time seconds
	std::this_thread::sleep_for(std::chrono::seconds(time));
	cout << "hello thread1!" << endl;
}
void threadHandle2(int time)
{
	//Let the child thread sleep time seconds ace this_thread is a namespace 
	std::this_thread::sleep_for(std::chrono::seconds(time));
	cout << "hello thread2!" << endl;
}
int main()
{
	//Create a thread object and pass in a thread function (as a thread entry function),
	//The new thread starts to run, without sequence, with the execution of the CPU scheduling algorithm 
	std::thread t1(threadHandle1, 2);
	std::thread t2(threadHandle2, 3);

	//The main thread runs here and waits for the sub thread to end before the main thread continues to run
	t1.join();
	t2.join();

	//Set the child thread as a separate thread, and the child thread has nothing to do with the main thread
	//View other threads when the main thread ends
	//However, whether the sub thread runs or not has nothing to do with the main thread
	//The sub thread is separated from the main
	//When running the program, you can't see any output printing of this sub thread
    //t1.detach();

	cout << "main thread done!" << endl;

	//After the main thread has finished running, check if the current process has unfinished child threads
	//The process will terminate abnormally
	return 0;
}


Under normal circumstances, the thread executes. In the main thread, you must wait for the sub thread to end, and the main thread executes downward. After the main thread runs, there can be no other sub threads running but not finished
At this point, the whole process will throw an exception and make an error. The exception is aborted

In linux, when the main thread ends, the sub thread will end automatically
However, at the language level, the control of sub threads is relatively strict
We can also solve this problem:

	//Set the child thread as a separate thread, and the child thread has nothing to do with the main thread
	//View other threads when the main thread ends
	//However, whether the sub thread runs or not has nothing to do with the main thread
	//The sub thread is separated from the main
	//When running the program, you can't see any output printing of this sub thread
    t1.detach();

Mutual exclusion between threads

Simulation station three window ticket selling program

Mutex = "lock" between threads_ Guard encapsulates mutex (automatically destructs the object out of scope on the stack to ensure that all threads can release the lock and prevent deadlock)

Multithreaded program
Race condition: the results of multithreaded program execution are consistent,
It will not produce different running results (race conditions exist) with different calling sequences of threads by the CPU.

Each thread needs to be completed within one instruction cycle, but multiple instructions are completely determined by the CPU scheduling. When the thread runs each instruction, it is possible that the CPU time slice has arrived and the thread is blocked. Wait for this thread to execute in the next round, then we can give the remaining time slice to this thread, and the thread continues to execute the following instructions. The two threads may reduce the same value, and then write back the same value
Therefore, we should ensure that this operation thread is safe!!! There is only one thread to do subtraction at a time

unique_ How to use lock: it is actually the encapsulation of mutex

Using lock_guard:

#include <iostream>
#include <thread>
#include <mutex>
#include <list>
using namespace std;

int ticketCount = 100;//There are 100 tickets in the station, which are sold together by three windows
std::mutex mtx;//A global mutex

//Thread function simulating ticket selling  
//lock_guard (copy structure and assignment function are deleted)
//unique_lock (pointer can be transferred, only copy construction and assignment with right value reference) 
void sellTicket(int index)
{
	while (ticketCount > 0)//Special case: ticketCount=1, so lock + double judgment is required
	{
		//Method 1: mtx.lock();
		{
			//Ensure that all threads can release locks to prevent deadlock problems_ PTR (copy construction and assignment function deleted)
			lock_guard<std::mutex> lock(mtx);//Method 2: with the idea of intelligent pointer, it automatically destructs and releases the lock when it comes out of the scope 
			if (ticketCount > 0)
			{
				//Critical area code snippet = > atomic operation = > inter thread mutually exclusive operation = > mutex
				cout << "window:" << index << "Sell No:" << ticketCount << "Ticket!" << endl;
				//cout << ticketCount << endl;
				ticketCount--;
			} 
		}
		//Method 1: mtx.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}

int main()
{
	list<std::thread> tlist;
	for (int i = 1; i <= 3; ++i)
	{
		tlist.push_back(std::thread(sellTicket, i));
	}

	for (std::thread &t : tlist)
	{
		t.join();
	}

	cout << "End of ticket sales at all windows!" << endl;

	return 0;
}

Keywords: C++ Multithreading

Added by swissmissflash on Sun, 12 Sep 2021 02:38:21 +0300