Creation, waiting, termination and separation of multithreads

1, Create a new thread

1. Header file: < pthread h>
2. Function: pthread_create(pthread_t *thread,const pyhread_attr_t *attr,void *(start_routine) (void ),void *arg);

namesignificance
pthread_tEquivalent to unsigned integer length
*threadID of the thread
const pyhread_attr_t *attrHalf of the properties of the thread are ignored. By default
void *(start_routine) (void )Thread routine is actually equivalent to the entry function of creating thread. It is essentially a callback function
void *argThe parameters of the function are passed if any, and are not set to NULL

3. Execute the new thread, and the main process still continues to execute
makefile file:

mythread:mythread.c
	gcc -o $@ $^ -lpthread  #The pthread library is cited
.PHONY:clean
clean:
	rm -f mythread

mythread file:

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s\n",msg);
    sleep(1);
  }
}

int main()
{
pthread_t tid;
  //Create thread
  pthread_create(&tid,NULL,Routine,(void*)"thread 1"); //Pass thread 1 parameter

  while(1)
  {
    printf("I am main thread!\n");
    sleep(2);
  }
  return 0;
}

result:

4. Check whether it belongs to a process. Print the id numbers of thread and process respectively. The id numbers of thread and process are consistent

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s: pid:%d,ppid:%d\n",msg,getpid(),getppid());
    sleep(1);
  }
}

int main()
{
pthread_t tid;
  //Create thread
  pthread_create(&tid,NULL,Routine,(void*)"thread 1"); //Pass thread 1 parameter

  while(1)
  {
    printf("main thread:pid:%d,ppid:%d\n",getpid(),getppid());
    sleep(2);
  }
  return 0;
}

5. PS - Al | head - 1 & & PS - Al | grep myThread
-50: Displays the current lightweight process
LWP: lightweight process ID
When OS scheduling is basic, LWP is used instead of PID!

In Linux, the application layer thread is 1:1 with the LWP of the kernel
6. Create a batch of threads

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s: pid:%d,ppid:%d\n",msg,getpid(),getppid());
    sleep(1);
  }
}

int main()
{
pthread_t tid[5];
  //Create thread
  for(int i = 0; i < 5; i++)
  {
    char buffer[64];
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //Pass thread 1 parameter
  }



  while(1)
  {
    printf("main thread:pid:%d,ppid:%d\n",getpid(),getppid());
    sleep(2);
  }
  return 0;
}


7. Display your thread ID:pthread_self()

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
  }
}

int main()
{
pthread_t tid[5];
  //Create thread
  for(int i = 0; i < 5; i++)
  {
    char buffer[64];
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //Pass thread 1 parameter
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }
  while(1)
  {
    printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
    sleep(2);
  }
  return 0;
}

Note: call the ID of your own thread: pthread_ Self() is similar to getpid(), but the type is% lu. In this case, the thread ID of the user level native thread library is obtained, and the relationship with LWP is 1:1

2, Thread waiting

1. Thread waiting: phread_join(), by default, waits in the form of blocking. If you don't wait, it may become a zombie process and cause memory leakage

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  int count = 0;
  while(count < 5)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
    count++;
  }
  return NULL;
}

int main()
{
pthread_t tid[5];
  //Create thread
  for(int i = 0; i < 5; i++)
  {
    char buffer[64];
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //Pass thread 1 parameter
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }

    printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());


  //Thread waiting
  for(int i = 0; i < 5; i++)
  {
    pthread_join(tid[i],NULL);
    printf("thread %d[%lu] ... quit!\n",i,tid[i]);
  }
  return 0;
}

2. Get exit code

int pthread_join(pthread_t thread, void **retval)
retval: get the exit code of the waiting thread, which is usually used to verify whether the code is running and the result is correct.

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  int count = 0;
  while(count < 5)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
    count++;
  }
  return (void*)10;
}

int main()
{
pthread_t tid[5];
  //Create thread
  for(int i = 0; i < 5; i++)
  {
    char *buffer=(char*)malloc(64);
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //Pass thread 1 parameter
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }

    printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());


  //Thread waiting
  for(int i = 0; i < 5; i++)
  {
    void *ret = NULL;
    pthread_join(tid[i],&ret); //Get exit code
    printf("thread %d[%lu] ... quit! code:%d\n",i,tid[i],ret);
  }
  return 0;
}


In addition: multithreading needs to consider exceptions, but it can't

3, Thread termination

1. Why wait?

(1) The space of the thread that has exited is not released and is still in the address space of the process
(2) Creating a new thread does not reuse the address space of the thread that just exited

2. Normal termination

(1). return: XXX represents the end of the whole process
(2). exit(): the whole process is terminated
(3). Terminate a thread: pthread_exit()
(4). pthread_cancel(): cancels a thread. The cancellation is successful. The exit code is - 1
(5). Pthread in main_ Cancel (TID [0]) cancel other threads (recommended), and cancel threads with subscript 0

In addition:
1. Can a new thread cancel the main thread? Yes, but not recommended
2. In general, the thread must be waiting, just as the child process must be waiting
3. The thread can not be join ed or not, but it needs to be separated

4, Thread separation

pthread_detach()

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  pthread_detach(pthread_self());
  char *msg = (char*)arg;
  int count = 0;
  while(count < 5)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
    count++;
  }
  pthread_exit((void*)19); //Thread exit code
 // return (void*)10;
}

int main()
{
pthread_t tid[5];
  //Create thread
  for(int i = 0; i < 5; i++)
  {
    char *buffer=(char*)malloc(64);
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //Pass thread 1 parameter
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }

   while(1){
     printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
    sleep(1);
   }
/*
  //Thread waiting
  for(int i = 0; i < 5; i++)
  {
    void *ret = NULL;
    pthread_join(tid[i],&ret); //Get exit code
    printf("thread %d[%lu] ... quit! code:%d\n",i,tid[i],ret);
  }
  */
  return 0;
}


How does the user layer know the corresponding thread?
There are many threads that need to be managed. Linux does not provide real threads, but only LWP, which means that the OS only needs to manage the execution flow of LWP kernel, and other data such as interfaces for users are managed by the thread library pthread library
pthread_t-type thread ID is essentially an address in a process address space.

Keywords: C C++ Linux

Added by alanlee79 on Wed, 16 Feb 2022 03:33:44 +0200