Thread: Multithreading in C pthreads - Where to learn

  1. #1
    Old Fashioned
    Join Date
    Nov 2016
    Posts
    137

    Multithreading in C pthreads - Where to learn

    I looked at the book recommendations thread and couldn't find one - I'm looking for a book which thoroughly covers pthreads and multithreading/parallelism in C.

    I can find about 100 tutorials using Google but it's almost a laughable joke because every single one is just like "This is how to create a thread" with some silly counting or hello world example.

    I want to learn how to properly manage multiple threads, learn all of the primitives like semaphores, mutexes, critical sections, etc... Learn the common pitfalls, learn debugging techniques, and also some architectures on how to properly lay out a multithreaded application.. Not just spin up a few threads for demo purposes.

    I find it very hard to believe that there isn't a good primer on this for the 40+ year old programming language C... Yet I have not been able to find one.

    Any recommendations? It could be videos, it could be a lengthy blog, or a book... I just want to learn this complex topic thoroughly.
    Last edited by Asymptotic; 08-19-2019 at 03:50 PM.
    If I was homeless and jobless, I would take my laptop to a wifi source and write C for fun all day. It's the same thing I enjoy now!

  2. #2
    Registered User
    Join Date
    May 2019
    Posts
    214
    Unfortunately I don't know of any texts in C, but then the subject is not so much a language concept, but a cross section of operating system details and computer science, with a bit of the CPU/hardware involved.

    You're going to find more material on various languages which apply generically once you know the interfaces to the critical components, and you listed most of them.

    There are a few interfaces which differ for each operating system, which all distill to the same basic notion of starting a thread which runs a given function (usually by function pointer), synchronization (mutexes/critical sections, waitable objects (condition variables), atomic operations, thread joins).

    You may find better results searching for "concurrency" instead of "threading". Searching for examples and blogs, books and articles on the specifics might also be fruitful. For example, search for autoreset events, condition variables, lock free concurrency, atomic operations, etc.

    You may also benefit from reading on OpenMP.

    One of the problems you face is that there are several general approaches to the purpose of threading.

    One would be parallel algorithms, so you may want to search on those. Parallel implementation of quicksort, for example (not all that common), or other simpler computational work (multithreaded image processing, for example).

    Another is merely background processing. In GUI, the user may launch a task which does not finish quickly enough to be handled within an event response function, so it is tossed off to a thread. There are patterns for this type of operation using callback notifications. Typically, the task is launched, and when finished some function is called (sometimes by pointer to function) as a callback to indicate that work is finished.

    Many such algorithms require a type of synchronization with the calling thread, known as joining. If a thread launches, say, 4 workers for a parallel task, the calling thread may require them to join the main thread. The join is a function, basically, which blocks the calling thread until all of the launched threads exit their function, synchronizing the calling thread so it does not continue until all the workers completed their task. This is in contrast to the callback/notification paradigm.

    Sometimes what you want is a thread that waits for jobs. This is akin to the background operations for a GUI application, but instead of launching a thread for each such function, a thread is launched that waits. The wait is performed on a condition variable (typical of *Nix). The idea is that the thread does nothing, quietly, until this condition variable is signaled. When it is, the thread "wakes up", presumably given some instruction through some means (sometimes packaged messages in a que, sometimes a que of pointers to functions, etc). The thread does the work, and then goes back to waiting for another signal.

    Lock free methods focus on atomic operations. These are implemented as intrinsic instructions usually. The CPU itself, when it supports this, has specialized instructions which synchronize an operation, like increment/decrement, read/write, add/subtract, compare-exchange. These operations are synchronized against a memory location across all CPUs in a mult-core machine such that only 1 CPU can perform the operation at a time, where any pending CPU is held only for a few clock cycles (somewhere from 20 to 60) awaiting it's turn. Imagine you need to release serial numbers, counted by an atomic integer. The increment instruction would be issued as an atomic increment, so that even if multiple threads attempt to increment simultaneously, they will be synchronized. This is considered a lock free approach because it does not use mutexes or critical sections (or the time associated with them), implementing a far more primitive kind of lock at the CPU associated only with the one instruction being synchronized.

    This gives rise to a number of design patterns. Locking a resource, for example, can be emulated using atomic compare-exchange. Say an integer is defined to hold a 0 if the resource it controls is available, and 1 otherwise. An atomic compare-exchange is attempted. This is a combined compare and exchange instruction which attempt to write a lock into the integer under atomic synchronization. If the value found there before the exchange was already a 1, then the lock was not obtained and the software must behave as though it didn't get the lock (maybe retry). If the value it found was 0, a 1 was atomically placed there by the exchange, and that thread is the one that "won" the lock. It then uses the controlled resource (holding that lock), until it's finished with the resource. To release the lock, write a 0 to that integer.

    I don't recall finding any comprehensive text describing these and myriad other concurrency design points. Some I've picked up from just experience, or read them (one at a time) in a text from 30 years ago.

    You'll probably find some text which focuses on some set of techniques, but I doubt a wide, comprehensive range is found in just 1 or 2 books.

    I've listed the highlights which occur to me off the cuff, which should give you plenty to search for.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multithreading help
    By nickman in forum C Programming
    Replies: 23
    Last Post: 09-19-2013, 01:23 PM
  2. Multithreading
    By ~Kyo~ in forum Game Programming
    Replies: 5
    Last Post: 09-14-2005, 09:30 PM
  3. You have to learn C in order to learn C++
    By gandalf_bar in forum A Brief History of Cprogramming.com
    Replies: 20
    Last Post: 07-16-2004, 10:33 AM
  4. learn multithreading
    By Micko in forum Windows Programming
    Replies: 5
    Last Post: 07-03-2004, 01:12 PM
  5. multithreading
    By thedumbmutt in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 11-13-2002, 11:54 AM

Tags for this Thread