Linux system programming - (pthread) thread use cases (separating properties, cleaning functions, etc.)

This article introduces the creation and basic use cases of threads under Linux, mainly case code; The related functions have been introduced in detail in the previous article.

1. Case code: thread creation

The following code demonstrates how to create a thread. You need to add - lpthread when compiling

Function prototype:

#include <pthread.h>
int pthread_create
(
pthread_t *thread, 
const pthread_attr_t *attr,
void *(*start_routine) (void *), 
void *arg
);

Example code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>

//[wbyq@wbyq linux_c]$ gcc app.c -lpthread

/*
Thread worker function
*/
void *thread_work_func(void *dev)
{
    int i;
    for(i=0;i<5;i++)
    {
        sleep(1);
        printf("The child thread is running.%d \n",i);
    }
    //Terminates the execution of the current thread
    pthread_exit(NULL);
}

int main(int argc,char **argv)
{
    /*1. Create child thread*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("Child thread creation failed.\n");
        return -1;
    }
    /*2. Wait for the child thread to finish - clear the space of the child thread*/
    pthread_join(thread_id,NULL);//--wait
    printf("The main thread terminates normally.\n");
    return 0;
}

2. How to receive the return value of the child thread?

When a thread is running, the default mode is combination mode or separation mode. If it is the default mode, resources need to be recycled after the thread is executed. By the way, you can introduce the status value returned when the sub thread ends.

Function prototype:

int pthread_join(pthread_t thread, void **retval);

Example code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>

//[wbyq@wbyq linux_c]$ gcc app.c -lpthread

/*
Thread worker function
*/
void *thread_work_func(void *dev)
{
    int i;
    for(i=0;i<5;i++)
    {
        sleep(1);
        printf("The child thread is running.%d \n",i);
    }
    //Terminates the execution of the current thread
    pthread_exit("1234567890");
}

int main(int argc,char **argv)
{
    /*1. Create child thread*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("Child thread creation failed.\n");
        return -1;
    }
    /*2. Wait for the child thread to finish - clear the space of the child thread*/
    char *p;
    pthread_join(thread_id,&p);//--wait
    printf("The main thread terminates normally.Return value of child line:%s\n",p);
    return 0;
}

3. Set the separation property of the thread

By default, the sub thread is in combination mode. You need to manually wait for the sub thread to finish and clean up the space; Sub threads can also be set to the separation property. After the sub thread runs, it cleans up its own space. The following example demonstrates how to set the sub thread to the separation mode.

Function prototype:

int pthread_detach(pthread_t thread);

Example code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>

//[wbyq@wbyq linux_c]$ gcc app.c -lpthread

/*
Thread worker function
*/
void *thread_work_func(void *dev)
{
    int i;
    for(i=0;i<5;i++)
    {
        sleep(1);
        printf("The child thread is running.%d \n",i);
    }
    //Terminates the execution of the current thread
    pthread_exit(NULL);
}

int main(int argc,char **argv)
{
    /*1. Create child thread*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("Child thread creation failed.\n");
        return -1;
    }
    /*2. Set the detach property of the thread*/
    pthread_detach(thread_id);
    while(1)
    {
        printf("The main thread is running.\n");
        sleep(1);
    }
    return 0;
}

4. Register thread cleanup function

Thread cleanup function, which can be called automatically or manually when the thread exits, is used to clean up some resources that need to be released.

Function prototype:

//register
void pthread_cleanup_push(void (*routine)(void *),void *arg); 
//release
void pthread_cleanup_pop(int execute);

Example code:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>

//[wbyq@wbyq linux_c]$ gcc app.c -lpthread

//Thread cleanup function
void thread_clear_work_func(void *dev)
{
    printf("The cleanup function of the thread is called.\n");
    /*
    Do some resource cleanup.
    For example: free up the space requested by malloc, close open files, etc
    */
}

/*
Thread worker function
*/
void *thread_work_func(void *dev)
{
    int i;
    //Register cleanup function
    pthread_cleanup_push(thread_clear_work_func,NULL); 
    for(i=0;i<5;i++)
    {
        sleep(1);
        printf("The child thread is running.%d \n",i);
    }

    //Terminates the execution of the current thread
    pthread_exit(NULL);
    
    //Release cleanup function
    pthread_cleanup_pop(1); 
}

int main(int argc,char **argv)
{
    /*1. Create child thread*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("Child thread creation failed.\n");
        return -1;
    }
    /*2. Set the detach property of the thread*/
    pthread_detach(thread_id);
    
    sleep(3);
    //Unassigned child thread end
    pthread_cancel(thread_id);

    while(1)
    {
        printf("The main thread is running.\n");
        sleep(1);
    }
    return 0;
}

5. Set the stack space size through ulimit command

pthread_ When creating a thread, if the allocation stack size is not specified, the system will allocate the default value. The method to view the default value is as follows:

[root@tiny4412 ]#ulimit -s
10240

The unit of 10240 above is KB, that is, the default thread stack space is 10M

You can also view it through ulimit -a command, where stack size also represents the size of stack space.

[root@tiny4412 ]#ulimit -a
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                10240
-c: core file size (blocks)        0
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      7512
-n: file descriptors               1024
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0

Set stack space size: ulimit - s < stack space size >

[root@tiny4412 ]#ulimit -s 8192 / / set stack space size
[root@tiny4412 ]#ulimit -s / / view the stack space
8192                          //Size 8M

Note: stack space settings can only be set under super administrator user permissions.

The stack space of each thread is independent. If the stack space overflows, the program will have a segment error. If a process has 10 threads, the allocated stack space is 10 * < stack size of each thread >

For example:

int main(int argc,char **argv)
{
	char buff[1024*1024*10];  //Define an array in the stack space. If the total size of the stack space is exceeded, the program will crash.
	printf("hello world!\n");
	return 0;
}

Keywords: C++ Linux Operation & Maintenance

Added by davser on Sun, 09 Jan 2022 16:26:58 +0200