- How to Create a Linux Thread in C
- The History of Thread Usage on Linux
- Working Logic of Threads
- Thread Creation in C
- Thread Types
- Thread Termination
- Why Are Threads Created?
- Kernel Thread – Linux Device Driver Tutorial Part 19
- Process
- Threads
- Thread Management
- Types of Thread
- User Level Thread
- Kernel Level Thread
- Kernel Thread Management Functions
- Create Kernel Thread
- kthread_create
- Start Kernel Thread
- wake_up_process
- Stop Kernel Thread
- kthread_stop
- Other functions in Kernel Thread
- kthread_should_stop
- kthread_bind
How to Create a Linux Thread in C
Using the pthread library, you can perform low-level thread management for high-performance programming.
Readers like you help support MUO. When you make a purchase using links on our site, we may earn an affiliate commission. Read More.
On Linux, you can create and manage threads in C/C++ using the POSIX thread (pthread) library. Unlike other operating systems, there is little difference between a thread and a process in Linux. That’s why Linux often refers to its threads as light-weight processes.
Using the pthread library, you can create threads, wait for them to terminate, and terminate them explicitly.
The History of Thread Usage on Linux
Before Linux version 2.6, the main thread implementation was LinuxThreads. This implementation had significant limits in terms of performance and synchronization operations. A limit on the maximum number of threads that could run restricted them to in the 1000s.
In 2003, a team led by developers from IBM and RedHat succeeded in making the Native POSIX Thread Library (NPTL) project available. It was first introduced in RedHat Enterprise version 3 to resolve performance issues with the Java Virtual Machine on Linux. Today, the GNU C library contains implementations of both threading mechanisms.
Neither of these is an implementation of green threads, which a Virtual Machine would manage and run in purely user mode. When you use the pthread library, the kernel creates a thread each time a program starts.
You can find thread-specific information for any running process in the files under /proc//task. This is the standard location for process information under the procfs Linux standard. For single-thread applications, it will appear that there is a task record with the same value as the PID under this directory.
Working Logic of Threads
Threads are like processes currently running on the operating system. In single-processor systems (e.g. microcontrollers), the operating system kernel simulates threads. This allows transactions to run simultaneously through slicing.
A single-core operating system can only really run one process at a time. However, in multi-core or multi-processor systems, these processes can run simultaneously.
Thread Creation in C
You can use the pthread_create function to create a new thread. The pthread.h header file includes its signature definition along with other thread-related functions. Threads use the same address space and file descriptors as the main program.
The pthread library also includes the necessary support for mutex and conditional operations required for synchronization operations.
When you’re using the functions of the pthread library, you must ensure the compiler links the pthread library into your executable. If necessary, you can instruct the compiler to link to the library using the -l option:
gcc -o test test_thread.c -lpthread
The pthread_create function has the following signature:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
It returns 0 if the procedure is successful. If there is a problem, it returns a non-zero error code. In the above function signature:
- The thread parameter is of type pthread_t. The created thread will always be accessible with this reference.
- The attr parameter lets you specify custom behavior. You can use a series of thread-specific functions starting with pthread_attr_ to set up this value. Possible customizations are the scheduling policy, stack size, and detach policy.
- start_routine specifies the function that the thread will run.
- arg represents a generic data structure passed to the function by the thread.
Here’s an example application:
#include
#include
#include
#include
void *worker(void *data)
char *name = (char*)data;
for (int i = 0; i < 120; i++)
usleep(50000);
printf("Hi from thread name = %s\n", name);
>
printf("Thread %s done!\n", name);
return NULL;
>
int main(void)
pthread_t th1, th2;
pthread_create(&th1, NULL, worker, "X");
pthread_create(&th2, NULL, worker, "Y");
sleep(5);
printf("Exiting from main program\n");
return 0;
>
Thread Types
When a thread returns from the main() function in an application, all threads terminate and the system frees up all resources the program used. Likewise, when exiting any thread with a command like an exit(), your program will terminate all threads.
With the pthread_join function, you can wait for a thread to terminate instead. The thread using this function will block until the expected thread terminates. The resources they use from the system are not return even in cases such as the termination of joinable threads, unscheduled by the CPU, or even failing to join with ptread_join.
Sometimes there are situations where joining with pthread_join does not make sense; if it’s impossible to predict when the thread will end, for example. In this case, you can ensure that the system returns all resources automatically at the point where the thread returns.
To achieve this, you should start the relevant threads with the DETACHED status. When starting a thread, DETACH status can be set via a thread attribute values or with the pthread_detach function:
int pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int pthread_detach(pthread_t thread);
Here’s an example use of pthread_join(). Replace the main function in the first program with the following:
int main(void)
pthread_t th1, th2;
pthread_create(&th1, NULL, worker, "X");
pthread_create(&th2, NULL, worker, "Y");
sleep(5);
printf("exiting from main program\n");
pthread_join(th1, NULL);
pthread_join(th2, NULL);
return 0;
>
When you compile and run the program, your output will be:
Hi from thread Y
Hi from thread X
Hi from thread Y
.
Hi from thread Y
exiting from main program
Hi from thread X
.
Hi from thread X
Thread X done!
Hi from thread Y
Thread Y done!
Thread Termination
You can cancel a thread with a call to pthread_cancel, passing the corresponding pthread_t id:
int pthread_cancel(pthread_t thread);
You can see this in action in the following code. Again, only the main function is different:
int main(void)
pthread_t th1, th2;
pthread_create(&th1, NULL, worker, "X");
pthread_create(&th2, NULL, worker, "Y");
sleep(1);
printf("====> Cancelling Thread Y!!\n");
pthread_cancel(th2);
usleep(100000);
printf("====> Cancelling Thread X!\n");
pthread_cancel(th1);
printf("exiting from main program\n");
return 0;
>
Why Are Threads Created?
Operating systems always try to run threads on one or more CPUs, either from a self-created list or from a user-created thread list. Some threads cannot run because they are waiting for an input/output signal from the hardware. They may also be waiting voluntarily, waiting for a response from another thread, or have another thread blocking them.
You can adjust the resources you allocate to threads that you create using pthread. This can be a custom scheduling policy, or you can choose scheduling algorithms such as FIFO or Round-robin if desired.
Kernel Thread – Linux Device Driver Tutorial Part 19
This article is a continuation of the Series on Linux Device Driver and carries the discussion on Linux device drivers and their implementation. The aim of this series is to provide easy and practical examples that anyone can understand. This is the Kernel Thread in Linux kernel driver – Linux Device Driver Tutorial Part 19.
Process
An executing instance of a program is called a process. Some operating systems use the term ‘task‘ to refer to a program that is being executed. The process is a heavyweight process. The context switch between the process is time-consuming.
Threads
A thread is an independent flow of control that operates within the same address space as other independent flows of control within a process.
One process can have multiple threads, with each thread executing different code concurrently, while sharing data and synchronizing much more easily than cooperating processes. Threads require fewer system resources than processes and can start more quickly. Threads, also known as lightweight processes.
One of the advantages of the thread is that since all the threads within the processes share the same address space, the communication between the threads is far easier and less time-consuming as compared to processes. This approach has one disadvantage also. It leads to several concurrency issues and requires synchronization mechanisms to handle the same.
Thread Management
Whenever we are creating a thread, it has to manage by someone. So that management follows like below.
- A thread is a sequence of instructions.
- CPU can handle one instruction at a time.
- To switch between instructions on parallel threads, the execution state needs to be saved.
- Execution state in its simplest form is a program counter and CPU registers.
- The program counter tells us what instruction to execute next.
- CPU registers hold execution arguments, for example, addition operands.
- This alternation between threads requires management.
- Management includes saving state, restoring state, deciding what thread to pick next.
Types of Thread
There are two types of threads.
User Level Thread
In this type, the kernel is not aware of these threads. Everything is maintained by the user thread library. That thread library contains code for creating and destroying threads, for passing messages and data between threads, for scheduling thread execution, and for saving and restoring thread contexts. So all will be in User Space.
Kernel Level Thread
Kernel level threads are managed by the OS, therefore, thread operations are implemented in the kernel code. There is no thread management code in the application area.
Anyhow each type of thread has advantages and disadvantages too.
Now we will move into Kernel Thread Programming. First, we will see the functions used in a kernel thread.
Kernel Thread Management Functions
There are many functions used in Kernel Thread. We will see each one by one. We can classify those functions based on functionalities.
- Create Kernel Thread
- Start Kernel Thread
- Stop Kernel Thread
- Other functions in Kernel Thread
For use the below functions you should include linux/kthread.h header file.
Create Kernel Thread
kthread_create
This API creates a kthread.
struct task_struct * kthread_create (int (* threadfn(void *data), void *data, const char namefmt[], . );
threadfn – the function to run until signal_pending(current).
data – data ptr for threadfn .
namefmt[] – printf-style name for the thread.
. – variable arguments
This helper function creates and names a kernel thread. But we need to wake up that thread manually. When woken, the thread will run threadfn() with data as its argument.
threadfn can either call do_exit directly if it is a standalone thread for which no one will call kthread_stop , or return when ‘ kthread_should_stop ‘ is true (which means kthread_stop has been called). The return value should be zero or a negative error number; it will be passed to kthread_stop .
It Returns task_struct or ERR_PTR(-ENOMEM) .
Start Kernel Thread
wake_up_process
int wake_up_process (struct task_struct * p);
p – The process to be woken up.
Attempt to wake up the nominated process and move it to the set of runnable processes.
It returns 1 if the process was woken up, 0 if it was already running.
It may be assumed that this function implies a write memory barrier before changing the task state if and only if any tasks are woken up.
Stop Kernel Thread
kthread_stop
int kthread_stop ( struct task_struct *k);
k – thread created by kthread_create .
Sets kthread_should_stop for k to return true , wakes it and waits for it to exit. Your threadfn must not call do_exit itself, if you use this function! This can also be called after kthread_create instead of calling wake_up_process : the thread will exit without calling threadfn .
It Returns the result of threadfn , or –EINTR if wake_up_process was never called.
Other functions in Kernel Thread
kthread_should_stop
should this kthread return now?
int kthread_should_stop (void);
When someone calls kthread_stop on your kthread, it will be woken and this will return true. You should then return, and your return value will be passed through to kthread_stop .
kthread_bind
void kthread_bind (struct task_struct *k, unsigned int cpu);