Home > Back-end >  Meaning of pthread_create function and its parameters
Meaning of pthread_create function and its parameters

Time:07-06

I don't understand deeply the pthread_create function and its parameters in c language.

int pthread_create( 
   pthread_t *thread,
   const pthread_attr_t *attr,
   void *(*start_routine)(void*),
   void *arg);
  • Why is the first parameter and the second parameter a pointer?
  • Why do people write NULL mostly for the second parameter? What can we write instead of NULL? Could you please give an example for a thread attribute?
  • void*(*start_routine)(void*) What is the meaning of all these pointers?

sorry if my questions don't make sense and thank you for your help.

CodePudding user response:

  • Why is the first parameter and the second parameter a pointer?

The first parameter is a "return parameter": That's where you get your created thread. The function itself returns a status/error indication.

The second parameter could theoretically have been passed by value, but - it's passed by address.

  • Why do people write NULL mostly for the second parameter?

Because that means the thread is created with the default attributes.

  • What can we write instead of NULL?

You can set fields in a pthread_attr_t structure, then pass its address.

  • Could you please give an example for a thread attribute?

Here are a few:

  Thread attributes:
                   Detach state        = PTHREAD_CREATE_DETACHED
                   Scope               = PTHREAD_SCOPE_SYSTEM
                   Inherit scheduler   = PTHREAD_EXPLICIT_SCHED
                   Scheduling policy   = SCHED_OTHER
                   Scheduling priority = 0
                   Guard size          = 0 bytes
                   Stack address       = 0x40197000
                   Stack size          = 0x3000000 bytes

This is actually the output of a sample program from the pthread_attr_init man page.

  • void*(*start_routine)(void*) - What is the meaning of all these pointers?

It's a function pointer, to a function which takes a void-pointer and returns a void-pointer. That's the function that the new thread will execute.

CodePudding user response:

Just to add one thing to the answer by @einpoklum and elaborate on the 4th argument void * arg:

Often you might want to add multiple arguments to your callback function (the 3rd argument in the pthread_create function) instead of just one. To do this, you create a struct which includes your arguments and initialize it to the correct values before passing it to the pthread_create function.

To learn more about how to do it, check out this post by @sigjuice or play with the code below:

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


struct Node {
  struct Node *next_node;
  struct Node *previous_node;
  int value;
};

struct DoublyLinkedList {
  struct Node *head;
  struct Node *tail;
  int size;
};

struct ThreadArguments {
  struct DoublyLinkedList *list; 
  struct Node *node_ascending;
  struct Node *node_descending;
};

int IsListEmpty(struct DoublyLinkedList *ptr) {
  int bool = 0;
  if (ptr->head != NULL) bool = 1;
  return bool;
}

void InsertToList(struct DoublyLinkedList *list, int n) {
  struct Node *node = malloc(sizeof(struct Node));
  node->value = n;
  if (list->size == 0) {
    list->head = node;
  }
  node->previous_node = list->tail;
  if (list->tail != NULL) list->tail->next_node = node;
  list->tail = node;
  list->tail->next_node = NULL;
  list->size  ;
}

void InitDoublyLinkedList(struct DoublyLinkedList *list) {
  list->tail = NULL;
  list->head = list->tail;
  list->size = 0;
}

void InitDoublyLinkedListWithArray(struct DoublyLinkedList *list, int arr[], int arr_length) {
  InitDoublyLinkedList(list);
  size_t arr_size = arr_length/sizeof(arr[0]);
  for (int i = 0; i < arr_size; i  ) {
    InsertToList(list, arr[i]);
  }
}

void PrintList(struct DoublyLinkedList *list) {
  struct Node *node = list->head;
  while (node != NULL) {
    printf("%d\n", node->value);
    node = node->next_node;
  }
  printf("\n");
}

int GetIntSquared(int n) {
  return n*n;
}

static void *TransformValueAscending(void *args) {
  struct ThreadArguments *arguments = args;
  struct Node *node = arguments->list->head;
  int ctr = 0;
  int limit = arguments->list->size / 2;
  while (node != NULL && ctr < limit) {
    arguments->node_ascending = node;
    node->value = GetIntSquared(node->value);
    node = node->next_node;
    ctr  ;
  }
}

static void *TransformValueDescending(void *args) {
  struct ThreadArguments *arguments = args;
  struct Node *node = arguments->list->tail;
  int ctr = 0;
  int limit = arguments->list->size / 2   arguments->list->size % 2;
  while (node != NULL && ctr < limit) {
    arguments->node_descending = node;
    node->value = GetIntSquared(node->value);
    node = node->previous_node;
    ctr  ;
  }
}


int main(int argc, char **argv) {
  struct DoublyLinkedList list;
  int arr[] = {2,3,4,5,6,7,8,9,10,11,12};
  InitDoublyLinkedListWithArray(&list, arr, sizeof(arr));
  // printf("%d\n", list.head->value);
  PrintList(&list);

  // create two new threads
  pthread_t thread_1;
  pthread_t thread_2;

  struct ThreadArguments args;
  args.list = &list;
  args.node_ascending = list.head;
  args.node_descending = list.tail;

  int error_code_t1 = pthread_create(&thread_1, NULL, TransformValueAscending, (void*)&args);
  void *thread_1_return_value;

  int error_code_t2 = pthread_create(&thread_1, NULL, TransformValueDescending, (void*)&args);
  void *thread_2_return_value;

  pthread_join(thread_1, &thread_1_return_value);
  pthread_join(thread_2, &thread_2_return_value);
  
  PrintList(&list);

  return 0;
}
  • Related