NDK14_C + + foundation: C + + thread

Keywords: Windows

NDK development summary

Article catalog

Threads, sometimes called lightweight processes, are the smallest unit of program execution.

C++11 thread

#include <thread>

void task(int i) {
	cout << "task:" << i << endl;
}

thread t1(task,100);
//Wait for the thread to end before continuing
t1.join();

POSIX Threads

POSIX portable operating system interface, which defines the interface standard that the operating system should provide for the application

Use configuration on Windows: download

cmake_minimum_required (VERSION 3.8)
include_directories("XXX/pthreads-w32-2-9-1-release/Pre-built.2/include")
#Set variable to x64 or x86
if(CMAKE_CL_64)
    set(platform x64)
else()
    set(platform x86)
endif()
link_directories("XXX/pthreads-w32-2-9-1-release/Pre-built.2/lib/${platform}")
#If "timespec": "struct" type redefinition setting appears
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_STRUCT_TIMESPEC")
# Add a source to the executable for this project.
add_executable (lsn6example "lsn6_example.cpp" "lsn6_example.h")
target_link_libraries(lsn6example pthreadVC2)

32-bit copy pthreadVC2.dll to windows/syswow64 directory
64 bit copy pthreadVC2.dll to windows/system32 directory

#include <pthread.h>
void *pthreadTask(void* args) {
	int* i = static_cast<int*>(args);
	cout << "posix thread :" << *i << endl;
	return 0;
}
pthread_t pid;
int pi = 100;
pthread_create(&pid, 0, pthreadTask, &pi);
//Wait for the end of the thread
pthread_join(pid,0);

Thread properties

Thread has properties, using pthread_attr_t represents

pthread_attr_t attr;
//Initializes the default values for all properties of threads supported by the operating system implementation in attr
pthread_attr_init(&attr);
pthread_attr_destroy(&attr);

Detach thread

Thread creation is non detached by default, when pthread_ When the join() function returns, the thread created is terminated and the system resources occupied are released
Detached thread cannot be waited by other threads, pthread_ The join is invalid. The thread plays its own.

//Set whether it is a detached thread
//PTHREAD_CREATE_DETACHED
//PTHREAD_CREATE_JOINABLE non separation
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

Scheduling strategy and priority

Windows cannot set successfully

//Set scheduling policy 
//Return 0 to set successfully
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
// SCHED_FIFO 
//	Real time scheduling strategy: first come first serve runs all the time once cpu is occupied. Run until a higher priority task arrives or abandons itself.
// SCHED_RR
//	Real time scheduling strategy: the time rotation system allocates a time period to execute this thread within the time period


//set priority
//Get the minimum and maximum priority of the corresponding policy
int max = sched_get_priority_max(SCHED_FIFO);
int min = sched_get_priority_min(SCHED_FIFO);
sched_param param;
param.sched_priority = max;
pthread_attr_setschedparam(&attr, &param);

Thread synchronization

When multiple threads read and write the same shared resource at the same time, conflicts may occur. It is necessary to introduce the thread "synchronization" mechanism, that is, each thread operates the shared resources orderly.

#include <pthread.h>
using namespace std;

queue<int> q;
void *pop(void* args) {
    //Multithreading security problems caused by unsynchronized threads
    // There will be repeated data fetches and exceptions
	if (!q.empty())
	{
		printf("Retrieve data:%d\n", q.front());
		q.pop();
	}
	else {
		printf("No data\n");
	}
	return 0;
}

int main()
{
	for (size_t i = 0; i < 5; i++)
	{
		q.push(i);
	}
	pthread_t pid[10];
	for (size_t i = 0; i < 10; i++)
	{
		pthread_create(&pid[i], 0, pop, &q);
	}
	system("pause");
	return 0;
}

Join mutex

queue<int> q;
pthread_mutex_t mutex;
void *pop(void* args) {
	// lock
	pthread_mutex_lock(&mutex);
	if (!q.empty())
	{
		printf("Retrieve data:%d\n", q.front());
		q.pop();
	}
	else {
		printf("No data\n");
	}
    // discharge
	pthread_mutex_unlock(&mutex);
	return 0;
}

int main()
{
    //Initialize mutex
	pthread_mutex_init(&mutex, 0);
	for (size_t i = 0; i < 5; i++)
	{
		q.push(i);
	}
	pthread_t pid[10];
	for (size_t i = 0; i < 10; i++)
	{
		pthread_create(&pid[i], 0, pop, &q);
	}
    //Release required
 	for (size_t i = 0; i < 10; i++)
	{
		pthread_join(pid[i], 0);
	}
	pthread_mutex_destroy(&mutex);
	system("pause");
	return 0;
}

Conditional variable

Condition variable is a mechanism for synchronization between threads, which mainly includes two actions: one thread waits for "condition of condition variable is established" and suspends; the other thread makes "condition is established" so as to wake up the suspended thread

```cpp
template <class T>
class SafeQueue {
public:
	SafeQueue() {
		pthread_mutex_init(&mutex,0);
	}
	~SafeQueue() {
		pthread_mutex_destory(&mutex);
	}
	void enqueue(T t) {
		pthread_mutex_lock(&mutex);
		q.push(t);
		pthread_mutex_unlock(&mutex);
	}
	int dequeue(T& t) {
		pthread_mutex_lock(&mutex);
		if (!q.empty())
		{
			t = q.front();
			q.pop();
			pthread_mutex_unlock(&mutex);
			return 1;
		}
		pthread_mutex_unlock(&mutex);
		return 0;
	}

private:
	queue<T> q;
	pthread_mutex_t mutex;
};
> The above template class stores data T,And use mutually exclusive lock to ensure queue Is thread safe. This is a production/Consumption mode.

> If you are taking out data, queue If it is empty, wait until the next time enqueue Add data.

> This is a typical production/consumption pattern, Add condition variable to make“ dequeue" Pending,Until it wakes up somewhere else

```cpp
#pragma once
#include <queue>
using namespace std;

template <class T>
class SafeQueue {
public:
	SafeQueue() {
		pthread_mutex_init(&mutex,0);
		pthread_cond_init(&cond, 0);
	}
	~SafeQueue() {
		pthread_mutex_destory(&mutex);
		pthread_cond_destory(&cond);
	}
	void enqueue(T t) {
		pthread_mutex_lock(&mutex);
		q.push(t);
		//Signal to suspend thread
		//Wake up a thread by the system
		//pthread_cond_signal(&cond);
		// When the broadcast corresponds to multiple consumers, multiple threads wait to wake up all
		pthread_cond_broadcast(&cond);
		pthread_mutex_unlock(&mutex);
	}
	int dequeue(T& t) {
		pthread_mutex_lock(&mutex);
		//May be awakened unexpectedly, so while loop
		while (q.empty())
		{
			pthread_cond_wait(&cond, &mutex);
		}
		t = q.front();
		q.pop();
		pthread_mutex_unlock(&mutex);
		return 1;
	}

private:
	queue<T> q;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
};
#include "lsn6_example.h"
#include <thread>
#include <pthread.h>

using namespace std;
#include "safe_queue.h"

SafeQueue<int> q;

void *get(void* args) {
	while (1) {
		int i;
		q.dequeue(i);
		cout << "consumption:"<< i << endl;
	}
	return 0;
}
void *put(void* args) {
	while (1)
	{
		int i;
		cin >> i;
		q.enqueue(i);
	}
	return 0;
}
int main()
{
	pthread_t pid1, pid2;
	pthread_create(&pid1, 0, get, &q);
	pthread_create(&pid2, 0, put, &q);
	pthread_join(pid2,0);
	system("pause");
	return 0;
}

Posted by saito on Tue, 16 Jun 2020 00:21:57 -0700