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;
}