Reader small image

You're reading from  Mastering Embedded Linux Programming - Third Edition

Product typeBook
Published inMay 2021
PublisherPackt
ISBN-139781789530384
Edition3rd Edition
Right arrow
Authors (2):
Frank Vasquez
Frank Vasquez
author image
Frank Vasquez

Frank Vasquez is an independent software consultant specializing in consumer electronics. He has over a decade of experience designing and building embedded Linux systems. During that time, he has shipped numerous devices including a rackmount DSP audio server, a diver-held sonar camcorder, and a consumer IoT hotspot. Before his career as an embedded Linux engineer, Frank was a database kernel developer at IBM where he worked on DB2. He lives in Silicon Valley.
Read more about Frank Vasquez

Chris Simmonds
Chris Simmonds
author image
Chris Simmonds

Chris Simmonds is a software consultant and trainer living in southern England. He has almost two decades of experience in designing and building open-source embedded systems. He is the founder and chief consultant at 2net Ltd, which provides professional training and mentoring services in embedded Linux, Linux device drivers, and Android platform development. He has trained engineers at many of the biggest companies in the embedded world, including ARM, Qualcomm, Intel, Ericsson, and General Dynamics. He is a frequent presenter at open source and embedded conferences, including the Embedded Linux Conference and Embedded World.
Read more about Chris Simmonds

View More author details
Right arrow

Chapter 17: Learning about Processes and Threads

In the preceding chapters, we considered the various aspects of creating an embedded Linux platform. Now, it is time to start looking at how you can use the platform to create a working device. In this chapter, I will talk about the implications of the Linux process model and how it encompasses multithreaded programs. I will look at the pros and cons of using single-threaded and multithreaded processes, as well as asynchronous message passing between processes and coroutines. Lastly, I will look at scheduling and differentiate between timeshare and real-time scheduling policies.

While these topics are not specific to embedded computing, it is important for a designer of any embedded device to have an overview of these topics. There are many good references on the subject, some of which I will list at the end of this chapter, but in general, they do not consider the embedded use cases. Due to this, I will be concentrating on the concepts...

Technical requirements

To follow along with the examples in this chapter, make sure the following software is installed on your Linux-based host system:

  • Python: Python 3 interpreter and standard library
  • Miniconda: Minimal installer for the conda package and virtual
    environment manager

See the section on conda in Chapter 16, Packaging Python, for directions on how to install Miniconda if you haven't already. The GCC C compiler and GNU make are also needed for this chapter's exercises, but these tools already come with most Linux distributions.

All the code for this chapter can be found in the Chapter17 folder of this book's GitHub repository: https://github.com/PacktPublishing/Mastering-Embedded-Linux-Programming-Third-Edition.

Process or thread?

Many embedded developers who are familiar with real-time operating systems (RTOS) consider the Unix process model to be cumbersome. On the other hand, they see a similarity between an RTOS task and a Linux thread, and they have a tendency to transfer an existing design using a one-to-one mapping of RTOS tasks to threads. I have, on several occasions, seen designs in which the entire application is implemented with one process containing 40 or more threads. I want to spend some time considering whether this is a good idea or not. Let's begin with some definitions.

A process is a memory address space and a thread of execution, as shown in the following diagram. The address space is private to the process, so threads running in different processes cannot access it. This memory separation is created by the memory management subsystem in the kernel, which keeps a memory page mapping for each process and reprograms the memory management unit on each context switch...

Processes

A process holds the environment in which threads can run: it holds the memory mappings, the file descriptors, the user and group IDs, and more. The first process is the init process, which is created by the kernel during boot and has a PID of one. Thereafter, processes are created by duplication in an operation known as forking.

Creating a new process

The POSIX function to create a process is fork(2). It is an odd function because, for each successful call, there are two returns: one in the process that made the call, known as the Parent, and one in the newly created process, known as the Child, as shown in the following diagram:

Figure 17.3 – Forking

Figure 17.3 – Forking

Immediately after the call, the child is an exact copy of the parent: it has the same stack, the same heap, the same file descriptors, and it executes the same line of code – the one following fork. The only way the programmer can tell them apart is by looking at the return value...

Threads

The programming interface for threads is the POSIX threads API, which was first defined in the IEEE POSIX 1003.1c standard (1995) and is commonly known as pthreads. It is implemented as an additional part of the libpthread.so C library. There have been two implementations of pthreads over the last 15 years or so: LinuxThreads and Native POSIX Thread Library (NPTL). The latter is much more compliant with the specification, particularly regarding the handling of signals and process IDs. It is pretty dominant now, but you may come across some older versions of uClibc that use LinuxThreads.

Creating a new thread

The function you can use to create a thread is pthread_create(3):

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
      void *(*start_routine) (void *), void *arg);

It creates a new thread of execution that begins in the start_routine function and places a descriptor in pthread_t, which is pointed to by thread...

ZeroMQ

Sockets, named pipes, and shared memory are the means by which inter-process communication take place. They act as the transport layers for the message passing process that makes up most non-trivial applications. Concurrency primitives such as mutexes and condition variables are used to manage shared access and coordinate work between threads running inside the same process. Multithreaded programming is notoriously difficult, and sockets and named pipes come with their own set of gotchas. A higher-level API is needed to abstract the complex details of asynchronous message passing. Enter ZeroMQ.

ZeroMQ is an asynchronous messaging library that acts like a concurrency framework. It has facilities for in-process, inter-process, TCP, and multicast transports, as well as bindings for various programming languages, including C, C++, Go, and Python. Those bindings, along with ZeroMQ's socket-based abstractions, allow teams to easily mix programming languages within the same...

Scheduling

The second big topic I want to cover in this chapter is scheduling. The Linux scheduler has a queue of threads that are ready to run, and its job is to schedule them on CPUs as they become available. Each thread has a scheduling policy that may be time-shared or real-time. The time-shared threads have a niceness value that increases or reduces their entitlement to CPU time. The real-time threads have priority in that a higher priority thread will preempt a lower one. The scheduler works with threads, not processes. Each thread is scheduled regardless of which process it is running in.

The scheduler runs when any of the following occurs:

  • A thread is blocked by calling sleep() or another blocking system call
  • A time-shared thread exhausts its time slice
  • An interruption causes a thread to be unblocked, for example, because of
    I/O completing

For background information on the Linux scheduler, I recommend that you read the chapter on process scheduling...

Summary

The long Unix heritage that is built into Linux and the accompanying C libraries provides almost everything you need in order to write stable and resilient embedded applications. The issue is that for every job, there are at least two ways to achieve the end you desire.

In this chapter, I focused on two aspects of system design: partitioning into separate processes, each with one or more threads to get the job done, and scheduling those threads. I hope that I shed some light on this and have given you the basis to study them further.

In the next chapter, I will examine another important aspect of system design:
memory management.

Further reading

The following resources provide further information about the topics that were introduced in this chapter:

  • The Art of Unix Programming, by Eric Steven Raymond
  • Linux System Programming, 2nd edition, by Robert Love
  • Linux Kernel Development, 3rd edition, by Robert Love
  • The Linux Programming Interface, by Michael Kerrisk
  • UNIX Network Programming, Volume 2: Interprocess Communications, 2nd Edition, by W. Richard Stevens
  • Programming with POSIX Threads, by David R. Butenhof
  • Scheduling Algorithms for Multiprogramming in a Hard-Real-Time Environment, by C. L. Liu and James W. Layland, Journal of ACM, 1973, vol 20, no 1, pp. 46-61
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering Embedded Linux Programming - Third Edition
Published in: May 2021Publisher: PacktISBN-13: 9781789530384
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime

Authors (2)

author image
Frank Vasquez

Frank Vasquez is an independent software consultant specializing in consumer electronics. He has over a decade of experience designing and building embedded Linux systems. During that time, he has shipped numerous devices including a rackmount DSP audio server, a diver-held sonar camcorder, and a consumer IoT hotspot. Before his career as an embedded Linux engineer, Frank was a database kernel developer at IBM where he worked on DB2. He lives in Silicon Valley.
Read more about Frank Vasquez

author image
Chris Simmonds

Chris Simmonds is a software consultant and trainer living in southern England. He has almost two decades of experience in designing and building open-source embedded systems. He is the founder and chief consultant at 2net Ltd, which provides professional training and mentoring services in embedded Linux, Linux device drivers, and Android platform development. He has trained engineers at many of the biggest companies in the embedded world, including ARM, Qualcomm, Intel, Ericsson, and General Dynamics. He is a frequent presenter at open source and embedded conferences, including the Embedded Linux Conference and Embedded World.
Read more about Chris Simmonds