Pthreads in Linux

July 10, 2021 0 Comments

Pthreads in Linux

Pthreads in Linux, User-level threads create with the help of user-level thread libraries. which will provide some interfaces through which we can create and manage user-level threads. each user-level thread will contain its own stack and code segment.

Each thread creates in the user space by thread library will maintain a data structure. thread library will provide a scheduler called a process scheduler or thread scheduler which is responsible for scheduling all user-level threads within a process.

In user-level threads other than stack and text segments rest of the segments are shared between threads.

POSIX Pthreads – may be provided as either a user or kernel library, as an extension to the POSIX standard.

Thread Creation:

#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
                          const pthread_attr_t *restrict attr,
                          void *(*start_routine)(void *),
                          void *restrict arg);
int pthread_join(pthread_t thread, void **retval);
noreturn void pthread_exit(void *retval);
Compile and link with -pthread.

The pthread_create() function starts a new thread in the calling process. The new thread starts execution by invoking start_routine(); arg pass as the sole argument of start_routine(). On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.

The pthread_join() function waits for the thread specified by a thread to terminate. If that thread has already terminated, then pthread_join() returns immediately. The thread specified by the thread must be joinable.

The pthread_exit() function terminates the calling thread and returns a value via retval that (if the thread is joinable) is available to another thread in the same process that calls pthread_join(3).

#include<stdio.h>
#include<pthread.h>
#include<string.h>
static void *threadfun(void *arg)
{
        char *s=(char *)arg;
        printf("%s\n",s);
        return (void *)strlen(s);
}
int main()
{
        pthread_t t1;
        void *res;
        int ret;
        ret = pthread_create(&t1,NULL,threadfun,"hello world");
        if (ret != 0) {
                printf("pthread create error\n");
                return -1;
        }
        ret = pthread_join(t1,&res);
        if (ret != 0) {
                printf("pthread join error\n");
                return -1;
        }

        printf("thread returned %ld \n",(long)res);

        return 0;
}

Thread attributes:

Each thread created using pthread_create has the following attributes.

  1. Detach state
  2. Scope
  3. Inherit scheduler
  4. Scheduling
  5. Stack

Detach state:

This attribute specifies the clean-up mode of a terminated thread.

#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr,
                                       int *detachstate);
Compile and link with -pthread.

The detach state attribute determines whether a thread created using the thread attributes object attr will create in a joinable or a detached state. The following values may be specified in detach state:

PTHREAD_CREATE_DETACHED: Threads that are creates using attr will create in a detached state.

PTHREAD_CREATE_JOINABLE: Threads that are creates using attr will create in a joinable state.

The default setting of the detach state attribute in a newly initialized thread attributes object is PTHREAD_CREATE_JOINABLE.

A thread starts in the detached state we can’t alter to joinable state(pthread_join()). A thread can be assigned to detach state during runtime using the function pthread_detach().

#define _GNU_SOURCE
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include<errno.h>
void display_thread_attr(pthread_attr_t *attr) {
        int ret, a;
        ret = pthread_attr_getdetachstate(attr, &a);
        if (ret != 0) {
                printf("pthread_attr_getdetachstate error \n");
                return;
        }
        printf("Detach state        = %s\n",
                        (a == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" :
                        (a == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE" :
                        "???");
}
static void *threadfun(void *arg)
{
        pthread_attr_t gattr;
        int ret;

        char *s=(char *)arg;
        ret = pthread_getattr_np(pthread_self(), &gattr);
        if (ret != 0) {
                printf("pthread_getattr_np error \n");
                return (void *)-1;
        }
        display_thread_attr(&gattr);
        exit(1);
}
int main()
{
        pthread_t th;
        pthread_attr_t attr;
        int ret;
        ret = pthread_attr_init(&attr);
        if (ret != 0) {
                printf("Pthread attribute init error\n");
                return -1;
        }

        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        if (ret != 0) {
                printf("Pthread attribute set detach error\n");
                return -1;
        }

        ret = pthread_create(&th,&attr,&threadfun,NULL);
        if (ret != 0) {
                printf("pthread create error\n");
                return -1;
        }

        ret = pthread_attr_destroy(&attr);
        if (ret != 0) {
                printf("pthread attr destroy error\n");
                return -1;
        }
        pause();
        return 0;
}

Scope:

This attribute specifies the resource contention scope for the current thread.

#include <pthread.h>
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(const pthread_attr_t *restrict attr,
                                 int *restrict scope);
Compile and link with -pthread.

The pthread_attr_setscope() function sets the contention scope attribute of the thread attributes to the object referred to by attr to the value specified in scope. POSIX.1 specifies two possible values for scope:

PTHREAD_SCOPE_SYSTEM: Thread is scheduling by kernel’s process scheduler. This is the default.

PTHREAD_SCOPE_PROCESS: The thread is scheduling by a process-level scheduler.

#define _GNU_SOURCE
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include<errno.h>
void display_thread_attr(pthread_attr_t *attr) {
        int ret, a;
        ret = pthread_attr_getscope(attr, &a);
        if (ret != 0) {
                printf("pthread_attr_getscope error \n");
                return;
        }
        printf("Scope         = %s\n",
                        (a == PTHREAD_SCOPE_SYSTEM) ? "PTHREAD_SCOPE_SYSTEM" :
                        (a == PTHREAD_SCOPE_PROCESS) ? "PTHREAD_SCOPE_PROCESS" :
                        "???");
}
static void *threadfun(void *arg)
{
        pthread_attr_t gattr;
        int ret;

        char *s=(char *)arg;
        ret = pthread_getattr_np(pthread_self(), &gattr);
        if (ret != 0) {
                printf("pthread_getattr_np error \n");
                return (void *)-1;
        }
        display_thread_attr(&gattr);
}
int main()
{
        pthread_t th;
        pthread_attr_t attr;
        int ret;
        ret = pthread_attr_init(&attr);
        if (ret != 0) {
                printf("Pthread attribute init error\n");
                return -1;
        }

        ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
        if (ret != 0) {
                printf("Pthread attribute set scope error %s\n", strerror(errno));
                return -1;
        }

        ret = pthread_create(&th,&attr,&threadfun,NULL);
        if (ret != 0) {
                printf("pthread create error\n");
                return -1;
        }

        ret = pthread_attr_destroy(&attr);
        if (ret != 0) {
                printf("pthread attr destroy error\n");
                return -1;
        }

        ret = pthread_join(th, NULL);
        if (ret != 0) {
                printf("pthread_join error \n");
                return -1;
        }

        return 0;
}

Inherit Scheduler:

#include <pthread.h>
int pthread_attr_setinheritsched(pthread_attr_t *attr,
                                       int inheritsched);
int pthread_attr_getinheritsched(const pthread_attr_t *restrict attr,
                                        int *restrict inheritsched);
Compile and link with -pthread.

The pthread_attr_setinheritsched() function sets the inherit-scheduler attribute of the thread attributes to object referred to by attr to the value specified in inheritsched. The following values may be specified in inheritsched:

PTHREAD_INHERIT_SCHED: Threads that are creates using attr inherit scheduling attributes from the creating thread; the scheduling attributes in attr are ignored. This is the default attribute.

PTHREAD_EXPLICIT_SCHED: Threads that are creates using attr take their scheduling attributes from the values specified by the attributes object.

#define _GNU_SOURCE
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include<errno.h>
void display_thread_attr(pthread_attr_t *attr) {
        int ret, a;
        ret = pthread_attr_getinheritsched(attr, &a);
        if (ret != 0) {
                printf("pthread_attr_getinheritsched error \n");
                return;
        }
        printf("Inherit scheduler        = %s\n",
                        (a == PTHREAD_INHERIT_SCHED) ? "PTHREAD_INHERIT_SCHED" :
                        (a == PTHREAD_EXPLICIT_SCHED) ? "PTHREAD_EXPLICIT_SCHED" :
                        "???");
}
static void *threadfun(void *arg)
{
        pthread_attr_t gattr;
        int ret;

        char *s=(char *)arg;
        ret = pthread_getattr_np(pthread_self(), &gattr);
        if (ret != 0) {
                printf("pthread_getattr_np error \n");
                return (void *)-1;
        }
        display_thread_attr(&gattr);
}
int main()
{
        pthread_t th;
        pthread_attr_t attr;
        int ret;
        ret = pthread_attr_init(&attr);
        if (ret != 0) {
                printf("Pthread attribute init error\n");
                return -1;
        }

        ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
        if (ret != 0) {
                printf("Pthread attribute inherit sched error %s\n", strerror(errno));
                return -1;
        }

        ret = pthread_create(&th,&attr,&threadfun,NULL);
        if (ret != 0) {
                printf("pthread create error\n");
                return -1;
        }

        ret = pthread_attr_destroy(&attr);
        if (ret != 0) {
                printf("pthread attr destroy error\n");
                return -1;
        }

        ret = pthread_join(th, NULL);
        if (ret != 0) {
                printf("pthread_join error \n");
                return -1;
        }

        return 0;
}

Scheduling:

Defines scheduling policy and priority.

#include <pthread.h>
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *restrict attr,
                                       int *restrict policy);
Compile and link with -pthread.

The pthread_attr_setschedpolicy() function sets the scheduling policy attribute of the thread attributes to the object referred to by attr to the value specified in the policy. The supported values for policy are SCHED_FIFO, SCHED_RR, and SCHED_OTHER.

Processes scheduled under one of the real-time policies (SCHED_FIFO, SCHED_RR) have a sched_priority value in the range 1 (low) to 99 (high).

All scheduling is preemptive: if a thread with a higher static priority becomes ready to run, the currently running thread will be preempted and returned to the waitlist for its static priority level. The scheduling policy determines the ordering only within the list of runnable threads with equal static priority.

SCHED_FIFO is a cooperative scheduler between the same priority process and priority pre-emptive across other process groups. SCHED _RR is a time scheduler across the same process priorities and priority pre-emptive across other
process.

#include <pthread.h>
int pthread_attr_setschedparam(pthread_attr_t *restrict attr,
                                     const struct sched_param *restrict param);
int pthread_attr_getschedparam(const pthread_attr_t *restrict attr,
                                     struct sched_param *restrict param);
Compile and link with -pthread.

The pthread_attr_setschedparam() function sets the scheduling parameter attributes of the thread attributes to object referred to by attr to the values specified in the buffer pointed to by param.

Scheduling parameters are maintained in the following structure:
           struct sched_param {
               int sched_priority;     /* Scheduling priority */
           };
#define _GNU_SOURCE
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include<errno.h>
void display_thread_attr(pthread_attr_t *attr) {
        int ret, a;
        struct sched_param p;
        ret = pthread_attr_getschedpolicy(attr, &a);
        if (ret != 0) {
                printf("pthread_attr_getschedpolicy error \n");
                return;
        }
        printf("Scheduling policy   = %s\n",
                        (a == SCHED_OTHER) ? "SCHED_OTHER" :
                        (a == SCHED_FIFO)  ? "SCHED_FIFO" :
                        (a == SCHED_RR)    ? "SCHED_RR" :
                        "???");
        ret = pthread_attr_getschedparam(attr, &p);
        if (ret != 0) {
                printf("pthread_attr_getschedparam error \n");
                return;
        }
        printf("Scheduling priority = %d\n", p.sched_priority);
}
static void *threadfun(void *arg)
{
        pthread_attr_t gattr;
        int ret;

        char *s=(char *)arg;
        ret = pthread_getattr_np(pthread_self(), &gattr);
        if (ret != 0) {
                printf("pthread_getattr_np error \n");
                return (void *)-1;
        }
        display_thread_attr(&gattr);
}
int main()
{
        pthread_t th;
        pthread_attr_t attr;
        int ret;
        ret = pthread_attr_init(&attr);
        if (ret != 0) {
                printf("Pthread attribute init error\n");
                return -1;
        }

        ret = pthread_create(&th,&attr,&threadfun,NULL);
        if (ret != 0) {
                printf("pthread create error\n");
                return -1;
        }

        ret = pthread_attr_destroy(&attr);
        if (ret != 0) {
                printf("pthread attr destroy error\n");
                return -1;
        }

        ret = pthread_join(th, NULL);
        if (ret != 0) {
                printf("pthread_join error \n");
                return -1;
        }

        return 0;
}

Stack:

Specifies stack address and size of the current thread. Default 2MB stack per thread. Each thread can assign from 16K to 8MB of stack size.

#include <pthread.h>
int pthread_attr_setstack(pthread_attr_t *attr,
                                 void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *restrict attr,
                                 void **restrict stackaddr,
                                 size_t *restrict stacksize);
Compile and link with -pthread.
#define _GNU_SOURCE
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include<errno.h>
void display_thread_attr(pthread_attr_t *attr) {
        int ret, a;
        size_t s;
        void *saddr;
        ret = pthread_attr_getguardsize(attr, &s);
        if (ret != 0) {
                printf("pthread_attr_getguardsize error \n");
                return;
        }
        printf("Guard size          = %zu bytes\n", s);

        ret = pthread_attr_getstack(attr, &saddr, &s);
        if (ret != 0 ){
                printf("pthread_attr_getstack error \n");
                return;
        }
        printf("Stack address       = %p\n", saddr);
        printf("Stack size          = %#zx bytes\n", s);
}
static void *threadfun(void *arg)
{
        pthread_attr_t gattr;
        int ret;

        char *s=(char *)arg;
        ret = pthread_getattr_np(pthread_self(), &gattr);
        if (ret != 0) {
                printf("pthread_getattr_np error \n");
                return (void *)-1;
        }
        display_thread_attr(&gattr);
}
int main()
{
        pthread_t th;
        pthread_attr_t attr;
        int ret;
        size_t st_size = 16900;
        void *sp;
        int align = getpagesize();
        ret = posix_memalign(&sp, align, st_size);
        if (ret != 0) {
                printf("posix_memalign error\n");
                return -1;
        }

        ret = pthread_attr_init(&attr);
        if (ret != 0) {
                printf("Pthread attribute init error\n");
                return -1;
        }

        ret = pthread_attr_setstack(&attr, sp, st_size);
        if (ret != 0) {
                printf("Pthread attr set stack error\n");
                return -1;
        }


        ret = pthread_create(&th,&attr,&threadfun,NULL);
        if (ret != 0) {
                printf("pthread create error\n");
                return -1;
        }

        ret = pthread_attr_destroy(&attr);
        if (ret != 0) {
                printf("pthread attr destroy error\n");
                return -1;
        }
        ret = pthread_join(th, NULL);
        if (ret != 0) {
                printf("pthread_join error \n");
                return -1;
        }

        return 0;
}

Share This: