“This is the fifth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

The POSIX Thread API is the first article in a series on how to write multithreaded programs using POSIX Threads.

In Linux, different threads in the same process:

Sharing:

  • Open file
  • The current working directory
  • Users and groups
  • Signal and signal handle

Have one’s own:

  • Thread Id
  • errnoError code (implemented using Thread-local)
  • priority
  • A separate thread stack

API

The following apis are defined in the header file pthread.h, and are linked to the pthread library when compiling with GCC, as shown below

gcc ./test.c -l pthread
Copy the code

pthread_create

Pthread_create is used to create a thread. This function returns 0 if the thread is successfully created, and an error code is returned if the thread fails to be created.

  • EAGAINSystem resources are insufficient or the number of threads in the process has reached the limit, we can passcat /proc/sys/kernel/threads-maxView the current system limit on the number of threads

  • EINVAL attrInvalid Settings in parameters
  • EPERM attrParameter has disallowed setting

This function defines the following parameters:

  • threadPointer to the thread ID into which the thread ID is saved after it is successfully created
  • attrUsed to set thread-specific parameters, if you want to use the default parameter NULL. For example, set the thread stack size and stack address (this scenario is common in embedded devices need to limit the thread stack size scenario).
  • start_routineA function to be executed by a thread whose input and output arguments are an untyped pointervoid*
  • argArguments passed to the function
#include <pthread.h>

int pthread_create(pthread_t *restrict thread,
                          const pthread_attr_t *restrict attr,
                          void *(*start_routine)(void *),
                          void *restrict arg);
Copy the code

pthread_self

Pthread_self is used to get the ID of the current thread.

 pthread_t pthread_self(void);
Copy the code

pthread_join

The call to pthread_JOIN will wait for the target thread to complete before exiting and get the result of the thread’s execution, which we will show as a Demo below.

int pthread_join(pthread_t thread, void **retval);
Copy the code

pthread_exit

Terminates the current thread (the thread that called this method) and sets the thread’s return value, which it will receive if another thread is blocking and waiting (calling pthread_join) to return.

void pthread_exit(void *retval);
Copy the code

pthread_detached

Detached Pthread_detached Is used to separate a thread. The thread that calls this method is recycled after it terminates and cannot wait (that is, no other thread can call pthread_join and wait).

int pthread_detach(pthread_t thread);
Copy the code

Demo

Create a thread and pass parameters

The following Demo shows how to create a thread, pass in parameters and get the thread’s return value and print it.

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

void* just_print(void *arg) {
    char *str = (char *)arg;
    printf("Thread say: %s\n", str);
    char *res_str = (char *)malloc(256);
    sprintf(res_str, "My thread id is %ld", pthread_self());
    return (void *)res_str;
}

int main(a) {
    pthread_t tid;
    void* res;
    printf("thread create\n");
    int s = pthread_create(&tid, NULL, just_print, "Hello");
    if (s) {
        perror("thread create failed");
        return - 1;
    }
    pthread_join(tid, &res);
    printf("thread exit \n");

    printf("Main thread recv msg: %s\n", (char *)res);
    return 0;
}
Copy the code

The output is as follows:

Limit thread stack size

As mentioned above, when creating a thread, we can change the behavior of the thread by setting parameters in the pthread_attr_t structure. This feature is useful in some special situations, such as:

  • If the program is running on an embedded device (memory limited), to save memory we can passpthread_attr_tTo reduce the size of the thread stack to save memory
  • We can also use this parameter to increase the stack memory of the thread to obtain more stack space when performing some more complex operations

The default thread stack size of the operating system can be checked by using ulimit -s

As shown in the Demo below, we initialize the pthread_attr_t structure with pthread_attr_init and then call pthread_attr_set_stackSIZE to set the thread stacksize.

Note that setting the thread stack size will return an error with an invalid parameter if the stack size is smaller than PTHREAD_STACK_MIN, or on some systems if the stack size is not a multiple of the system’s page size.

As shown in the Demo below, we use THREAD_STACK_SIZE to indicate the amount of stack space allocated to the thread, and ALLOC_SIZE to indicate the amount of stack space allocated to the thread by the method to execute.

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

#define THREAD_STACK_SIZE 4096 * 6
#define ALLOC_SIZE 4096 * 4

void* malloc_mem(void *arg) {
    char msg[ALLOC_SIZE];
    printf("stack malloc done! \n");
}

int main(a) {
    pthread_t tid;
    pthread_attr_t attr;
    if(pthread_attr_init(&attr) ! =0) {
        perror("init attr failed");
        return - 1;
    }
    int r = pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
    if(r ! =0) {
        printf("set stack size failed, err=%s\n", strerror(r));
        return - 1;
    }
    int size = 1024;
    int s = pthread_create(&tid, &attr, malloc_mem, &size);
    if (s) {
        perror("thread create failed:");
        return - 1;
    }
    pthread_join(tid, NULL);
    return 0;
}

Copy the code

Test case 1, THREAD_STACK_SIZE = ALLOC_SIZE = 4096 * 6, and the output looks like this:

The system prompts a Segmentation fault because the stack space is insufficient.

In test case 2, THREAD_STACK_SIZE = 4096 * 6 and ALLOC_SIZE = 4096 * 4, the output is as follows:

Test case 3 THREAD_STACK_SIZE = 4096 * 1, ALLOC_SIZE = 1024 The following output is displayed

Error: The stack space allocated by thread is smaller than PTHREAD_STACK_MIN