Linux foundation - threads

1. Thread concept

1.1 comparison between threads and processes

  1. Threads are similar to processes, both of which have PCB s
  2. The underlying functions of both are the same, and both use clone
  3. Processes can become threads
  4. Under Linux, thread is the smallest unit of execution; process is the smallest unit of allocated resources
  5. . from the perspective of the kernel, processes and threads are the same, with different PCBs, but the three-level page table pointing to memory resources in PCB is the same.

In the figure below, A is A process with only one PCB. b creates A thread with one more PCB, but they share in one resource.

1.2 resources shared between threads

  1. Document descriptor table
  2. Processing mode of each signal
  3. Current working directory
  4. User ID and group ID
  5. Memory address space

1.3 resources not shared between threads

  1. Thread id
  2. Processor field and stack pointer (kernel stack)
  3. Independent stack space (user space stack)
  4. errno variable
  5. Signal shielding word
  6. Scheduling priority

1.4 analysis of advantages and disadvantages of threads

1. Advantages:

  • Improve program concurrency
  • Low overhead, no need to reallocate memory
  • Convenient communication and data sharing

2. Disadvantages

  • Thread instability (library function implementation)
  • Thread debugging is difficult (gdb support is not good)
  • Threads cannot use unix classic events, such as signals

1.5 attention points of thread

1. As soon as the main thread ends, so will the sub thread (whether or not your sub thread has finished executing).
2. Variables are shared between threads.
3. In the creation function, errors cannot be printed with perror.

2. pthread analysis

2.1 check LWP No

Enter ps -elf in the terminal to view the LWP number of the thread

2.2 create thread function pthread_create

  • Header file: include < pthread. H >
  • Function: int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
  • Parameter analysis
    • Parameter 1: pthread_t *thread, where you need to pass a type of pthread_t to save the ID of the new thread created
    • Parameter 2: const pthread_attr_t *attr: thread property setting. If the default property is used, NULL will be passed. Here we usually use NULL when writing code, which is set to default.
    • Parameter 3: void *(*start_routine) (void *): function pointer to the function module that the new thread should load and execute. Write the function to be executed after the thread is created.
    • Parameter 4: void *arg: Specifies the parameter of the function to be called by the thread (that is, this parameter is to be passed to and executed in the function)
    • Return value: 0 for success and error number for failure. (it can't be printed with perror to judge whether there is any error in function execution)

Sample code

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>	
#include <string.h>
//Function to be executed by thread
void *run(void* arg)
{
	int i = (int)arg;
	printf("I'm number one%d Subthread\n",i+1)}

int main(void)  
{
	//Here I create pthread_t array to create multiple sub threads
	pthread_t tid[5];
	
	//This is used to save the error number generated when creating a thread
	int err;
	


 	//Create thread
 	for(int i = 0;i<5;i++)
	{
  		//Create a thread, pass the second parameter to NULL, and pass the third parameter to the execution function. Parameter 4 is the parameter of the incoming execution function
  		//The i I passed in here needs to be converted into void *
  		err = pthread_create(&tid[i],NULL,run,(void*)i);

		//error handling
		if (err != 0) 
		{
			//Error information processing, easy to display to the terminal
			fprintf(stderr, "can't create thread: %s\n", strerror(err)); 
			exit(1); 
		} 
  	}
	
	sleep(i);
	return 0;
 }

Note:
1. When the sub thread finishes executing the specified function (that is, the third parameter start_ After routine), the thread exits (the thread dies). Other threads can use pthread_join to get start_ The return value of the routine function, and the finished thread (corpse operation) is recycled.
2. When creating the thread function pthread_ After create, the new ID will be written to the first parameter (pthread_ In t * thread), ptthread can be used_ Self() function.

2.2 pthread_self get calling thread tid

  • Header file: include < pthread. H >
  • Function: pthread_t pthread_self(void);
printf("In mian thread id = %u \n",pthread_self());

Through pthread_ The self function gets the id. The id number of each thread is different.

2.3 pthread_exit thread exit function

  • Header file: include < pthread. H >
  • Function: void pthread_exit(void *retval);
  • Parameter: void *retval: the parameter passed when the thread exits. It can be the exit value or address. If it is the address, it cannot be the local address of the internal application of the thread.
  • Note:
    • Call the thread exit function. Note the difference between the exit function and the exit function. Exit in any thread causes the process to exit (once the process exits, it means that some processes terminate exit). Other threads are not finished. The master thread cannot return or exit when it exits.
    • pthread_ The memory unit that the exit or return pointer points to must be global or allocated with malloc, otherwise the memory error will occur!

2.4 pthread_join recycle thread

  • Header file include < pthread. H >
  • Function int pthread_join(pthread_t thread, void **retval);
  • Parameter analysis
    • Parameter 1: pthread_t thread: tid of recycle thread
    • Parameter 2: void **retval: receive the return value passed by the exit thread. Generally, we fill in the blank for this parameter, so that this function can only recycle the process. If you need to use this return value, please see the following points
    • Return value: 0 for success, error number for failure
    • Note: there are many cases of the second parameter
      • If the thread returns through return, the return value of the thread function is stored in the cell that the return value points to.
      • If the thread thread is called pthread by another thread_ Cancel is terminated abnormally. The cell retval points to stores the constant PTHREAD_CANCELED.
      • If the thread thread calls pthread itself_ If exit is terminated, the unit retval points to is stored and passed to pthread_ Parameter for exit.
      • If you are not interested in the end state of the thread, you can pass NULL to the retval parameter.

2.4 pthread_cancel to end other threads

  • Header file: include < pthread. H >
  • Function: int pthread_cancel(pthread_t thread);
  • Parameter 1: pthread_t thread: tid of the thread to end

2.5 pthread_detach detaches threads

  • Header file: include < pthread. H >
  • Function: int pthread_detach(pthread_t tid);
  • Parameter 1: pthread_t thread:: detach thread tid
  • Return value: 0 for success and error number for failure.

Resolution:

  1. The function and pthread_ Similar to join, its function is that the thread can also be set to the detach state, so that once terminated, the thread immediately reclaims all the resources it occupies, without retaining the termination state.
  2. Pthread cannot be called on a thread that is already in the detach state_ Join, such a call will return EINVAL. (that is, if pthread has been called on a thread_ Detach can no longer call pthread_join).

3. Sample code

3.1. c code example

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

int var = 100;	//Define a global variable to verify variable sharing
void *run(void* arg)
{
	int i = (int)arg;
 
	sleep(i);
 
	if(i == 1)	//The first thread modifies variables	
	{
  		var =111;
  		printf("var = %d\n",var);
  		return var;
  	}
  	else if(i == 3)	//The fourth thread modifies variables
 	{
  		var =333;
  		printf("var = %d\n",var);
  		printf("I'm number one%d Thread, I finished myself\n",i+1);
  		//End your pthread_exit. As long as other threads are still there, you can't return or exit after committing suicide
  		pthread_exit((void *)var);
		//pthread_detach(pthread_t tid) can kill other threads
 	} 
 	else
 	{
  		pthread_exit((void *)var);
 	}
	return NULL;
}
int main(void)  
{
 	pthread_t tid[5];
 	int *ret[5];
 	int i;
	//Look at the thread ID and process ID of the main thread
 	printf("In mian thread id = %u , pid = %u\n",pthread_self(),getpid());

	//Create thread
 	for(i = 0;i<5;i++)
 	{
  		//Create a thread, pass the second parameter to NULL, and pass the third parameter to the execution function. Parameter 4 is the parameter of the incoming execution function
  		pthread_create(&tid[i],NULL,run,(void*)i);
  	}
	
	//Recycle multiple sub threads pthread_join, do not recycle will cause zombie thread
	for(i = 0;i<5;i++)
 	{
  		//The secondary pointer provides memory reading and modification, and the return value of the thread exists in * ret
  		pthread_join(tid[i],(void**)&ret[i]);
 
 	}
	
	printf("in main id = %u, var = %d\n",pthread_self(),var);
 	sleep(i);
	return 0;
}

3.2. C + + encapsulation thread

Header file

#ifndef BASETHRED_H
#define BASETHRED_H

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

class CBaseThread
{
public:
 	CBaseThread();
 	~CBaseThread();
	
	//Create and start the thread
 	void start();
	
	//The user-defined processing function is defined as a virtual function. Each subclass's own run is different
 	virtual int run()=0;
 private:
 	//For the processing function of thread class, please note that it should be set as static
	 static void* rountine(void *arg);
protected:
 	bool m_bRun; //Operation flag bit
 	bool m_bJoin; //Recycle or not
 	pthread_t m_tid; //Thread ID
}
#endif

cpp file

#include "CBase_pthread.h"
CBaseThread::CBaseThread()
:m_bRun(false),m_bJoin(false)
{
}

CBaseThread::~CBaseThread()
{
}

void CBaseThread::start()
{
 	//Determine whether the thread has been created
 	if(m_bRun == false)
 	{
 		//I'm here to pass this (CBaseThread class) in, and make a strong transition
  		if(pthread_create(&m_tid,NULL,rountine,(void*)this)!=0)
  		{
   			perror("create thread error:\n");
  		}
  	}
}

//Handle custom functions of subclasses
void* CBaseThread::rountine(void *arg)
{
 	//First, give him this message and force it back. Use this thr to receive it
 	CBaseThread *thr = (CBaseThread*)arg;
 	if(thr->m_bJoin)
 	{
  		//Self separation, no need to call join function to wait
  		//As soon as the thread terminates, it reclaims all the resources it occupies, without retaining the termination state.
  		pthread_detach(pthread_self());
  	}
  	
  	thr->m_bRun = true;
 	thr->run();  //User defined processing function
 	thr->m_bJoin = false;
 	
	pthread_exit(NULL);
	}
 }

Main function

#include "CBase_pthread.h"
#include <iostream>
using namespace std;
int main(void)
{
 	CBaseThread my_Thread;
 	my_Thread.start();
 	
 	sleep(1);
 	return 0;
}

Keywords: Linux Unix

Added by pcwizzzz on Thu, 18 Jun 2020 08:51:58 +0300