0% found this document useful (0 votes)
10 views34 pages

L2 Threads

The lecture covers tasks and threads in modern C++, focusing on program execution, task parallelism, and data parallelism. It discusses the evolution of C++ regarding multithreading, ownership, lifetime, and RAII principles, as well as synchronization techniques to avoid data races. The session emphasizes the importance of managing thread lifetimes and the implications of concurrent access to shared data.

Uploaded by

Chang Jingyan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views34 pages

L2 Threads

The lecture covers tasks and threads in modern C++, focusing on program execution, task parallelism, and data parallelism. It discusses the evolution of C++ regarding multithreading, ownership, lifetime, and RAII principles, as well as synchronization techniques to avoid data races. The session emphasizes the importance of managing thread lifetimes and the implications of concurrent access to shared data.

Uploaded by

Chang Jingyan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Lecture 2 – Tasks and Threads

(in Modern C++)


CS3211 Parallel and Concurrent Programming
Outline
• Tasks
• A bit of C++ history
• Threads in C++
• Ownership, lifetime, and RAII in C++
• Preliminary for synchronizing threads in C++

CS3211 L2 - Tasks and Threads 2


Program Execution
• 3 main steps:
• Decomposition of the computations

• Assigning tasks to threads

• Orchestration
• Structuring communication
• Adding synchronization to preserve dependencies if necessary
• Organizing data structures in memory
• Scheduling tasks

• Mapping of threads to physical cores

CS3211 L2 - Tasks and Threads 3


Distributing work to threads – task parallelism
• Divide the work into tasks to make the threads specialists
• Same types of tasks assigned to the same thread (aka pipeline)
• Divide the work by task type to separate concerns
• Dividing a sequence of tasks among threads to achieve a complex
solution
• Pipeline: each thread is responsible for a stage of a pipeline
• Use task pools and the number of threads to serve the task pool

CS3211 L2 - Tasks and Threads 4


Distributing work to threads – data parallelism
• Dividing data

CS3211 L2 - Tasks and Threads 5


Outline
• Tasks
• A bit of C++ history
• Threads in C++
• Ownership, lifetime, and RAII in C++

CS3211 L2 - Tasks and Threads 6


C++ history
• 1998 –the original C++ standard published
• No support for multithreading!
• Use external libraries to manage threads in your C/C++ programs
• Pthread
• 2011 – C++11 (or C++0x) standard published
• new “train model” of releases
• support of multithreaded programs
• 2014
• 2017
• 2020
• 2023
CS3211 L2 - Tasks and Threads 7
C++98
• Does not acknowledge the existence of threads
• Effects of language elements assume a sequential abstract machine
• No memory model
• Multithreading was dependent on compiler-specific extensions
• C APIs, such as POSIX C standard and Microsoft Windows API, used in C++
• Very few formal multithreading-aware memory models provided by compiler
vendors
• Application frameworks, such as Boost and ACE, wrap the underlying
platform-specific APIs
• Provide higher-level facilities for multithreading

CS3211 L2 - Tasks and Threads 8


C++11 multithreading
• Write portable multithreaded code with guaranteed behavior
• Multithreading without relying on platform-specific extensions
• Thread-aware memory model
• Includes classes for managing threads, protecting shared data,
synchronization between threads, low-level atomic operations
• Use of concurrency to improve application performance
• Take advantage of the increased computing power
• Low abstraction penalty - C++ classes wrap low-level facilities
• Low-level facilities: atomic operations library

CS3211 L2 - Tasks and Threads 9


Managing threads
• Every program has at least one thread
• Started by the C++ runtime
• Runs main()
• Use std::thread to add threads

CS3211 L2 - Tasks and Threads 10


Creating a thread
• Line 11: creates a
tthread
• Identifying a thread
using get_id()

CS3211 L2 - Tasks and Threads 11


Starting threads
• There are different ways to start
threads:
1. Using a function (like pthreads)
• Lines 1-2: Thread with a function

2. Using a function object


• Lines 6-16: Thread with a function
object (callable type)

• Poll: PollEv.com​/ccris
Should line 20 declare and initialize a
thread?

CS3211 L2 - Tasks and Threads 12


NOT starting threads
Line 20 declares a function that
returns a thread:
• Declares my_thread function that
• takes a single parameter (of type
pointer-to-a-function-taking-
no-parameters-and-returning-
a-background_task-object) and
• returns a std::thread object
• Does not launch a new thread!

CS3211 L2 - Tasks and Threads 14


Starting threads (cont)
Line 20: Declares a function that
returns a thread
Lines 24-25: Create a thread with a
function object
- Line 25 is the recommended way to
declare threads (CS3211)

Lines 30-33: Create a thread with a


lambda expression (local function
instead of a callable object)

CS3211 L2 - Tasks and Threads 15


Starting threads - summary

4 different ways:
1-2 Thread with a function
6-16 Thread with a function
object (callable type)
24-25 Thread with a function
object
30-33 Thread with a lambda
expression (local function
instead of a callable object)
16

CS3211 L2 - Tasks and Threads


Wait or detach?
• Wait for a thread to finish • Detach the thread
• Use join() on the thread • Use detach()
instance, exactly once • Extra care is needed with local
• Use joinable() to check that a variables passed to the thread
thread can be joined

CS3211 L2 - Tasks and Threads 17


Waiting

• Make sure to
join the thread
even when
there is an
exception!

CS3211 L2 - Tasks and Threads 18


Detach
• Detach a thread
• Once detached, the thread is not
joinable

CS3211 L2 - Tasks and Threads 19


Detach (cont)
• Possible issue: local variables
passed as parameters to the
thread function might end their
lifetime before the thread ends

CS3211 L2 - Tasks and Threads 20


Passing arguments to a thread function
• Lines 1-2: Passing a function and
arguments by value to create a
thread

• Lines 11-18: possible issue: oops


might exit before the buffer is
converted to std::string within
the new thread (passing a reference
to buffer)

• Lines 21-28: the conversion


happens before passing the
argument to the thread through an
explicit cast

CS3211 L2 - Tasks and Threads 21


Passing arguments by reference
• Lines 31-39: data is
passed by value
(copy)
• Issue: changes to
the data are not
visible after thread
join

• Line 41: Wrap the


arguments in
std::ref

CS3211 L2 - Tasks and Threads 22


Lifetime
• The lifetime of an object begins when:
• storage with the proper alignment and size for its type is obtained, and
• its initialization (if any) is complete (including default initialization via no constructor or trivial
default constructor) (except that of union and allocations by std::allocator::allocate)
• The lifetime of an object ends when:
• if it is of a non-class type, the object is destroyed (maybe via a pseudo-destructor call), or
• if it is of a class type, the destructor call starts, or
• the storage which the object occupies is released, or is reused by an object that is not nested
within it.
• Lifetime of an object is equal to or is nested within the lifetime of its storage,
see storage duration.
• The lifetime of a reference begins when its initialization is complete and ends as if
it were a scalar object.
Note: the lifetime of the referred object may end before the end of the
lifetime of the reference, which makes dangling references possible.
CS3211 L2 - Tasks and Threads 23
Ownership in C++
• An owner is an object containing a pointer to an object allocated by new
for which a delete is required
• Every object on the free store (heap, dynamic store) must have exactly one
owner
• (this rule is not enforced, but advisable)
• C++’s model of resource management is based on the use of constructors
and destructors
• For scoped objects, destruction is implicit at scope exit
• For objects placed in the free store (heap, dynamic memory) using new, delete is
required

Objects can also be allocated using malloc() and deallocated using free() (or similar
functions), but the techniques described for new and delete apply to those also
Source: https://www.stroustrup.com/resource-model.pdf

CS3211 L2 - Tasks and Threads 24


RAII - Resource Acquisition Is Initialization
• C++ programming technique
• Binds the life cycle of a resource that must be acquired before use
(allocated heap memory, thread of execution, open socket, open file,
locked mutex, disk space, database connection—anything that exists
in limited supply) to the lifetime of an object.

CS3211 L2 - Tasks and Threads 25


Ownership of a thread
• std::thread instances own a resource
• Manage a thread of execution
• Instances of std::thread are
• Movable
• are not copyable
• (Same ownership semantics as std::unique_ptr)

CS3211 L2 - Tasks and Threads 27


Transferring ownership of a thread
• Lines 11-19: Transfer ownership • Lines 21-28: Transfer ownership
of thread out of function of thread into a function

CS3211 L2 - Tasks and Threads 29


Outline
• Tasks
• A bit of C++ history
• Threads in C++
• Ownership, lifetime, and RAII in C++
• Preliminary for synchronizing threads in C++

CS3211 L2 - Tasks and Threads 30


Synchronizing multiple threads
1. Concurrent access to shared data
2. Concurrent actions

CS3211 L2 - Tasks and Threads 31


Synchronizing concurrent accesses
• If all shared data is read-only – no problem
• the data read by one thread is unaffected by another thread is reading the
same data
• Modifying shared data comes with many challenges
• Programs must be designed to ensure that changes to a chosen data
structure are correctly synchronized among threads
• Data structures are immutable (data never changes), or
• Protect data using some locking: external or internal

CS3211 L2 - Tasks and Threads 32


Structure of program data
• Every variable is an object, including
those that are members of other
objects.
• Every object occupies at least one
memory location.
• Variables of fundamental types such
as int or char occupy exactly one
memory location, whatever their size,
even if they’re adjacent or part of an
array.
• Adjacent bit fields are part of the
same memory location.

CS3211 L2 - Tasks and Threads 33


Concurrent access to the same memory location
• Two threads access the same memory x
location T1 T2
• Read-only data doesn’t need protection or
synchronization
• Either thread is modifying the data:
potential for a data race
• Data Race - for two accesses to a single
memory location from separate
threads
• no enforced ordering between accesses
• one or both of those accesses are not
atomic,
• AND if one or both accesses are a write
Causes undefined behavior
CS3211 L2 - Tasks and Threads 34
Avoid data races
• Code that must execute in isolation w.r.t. other program code
• To avoid data races:
• Locks
• Ordered atomics
• Transactional memory

CS3211 L2 - Tasks and Threads 37


Summary
• Introduced modern C++, std::thread and synchronization
• Lifetime
• Ownership
• RAII
• Data race

• Reference
• C++ Concurrency in Action, Second Edition
• Chapters 2, 3.1

CS3211 L2 - Tasks and Threads 38


There is no tutorial in Week 2
• Tutorial 0.5 (for weeks 2 & 3): a C++ primer as a writeup for your own
reference
• Study it on your own (if you are not familiar with modern C++)

• Tutorial classes start in week 4

• Appeal in Edurec after Tue, 5pm if you still don’t have a tutorial slot
allocation
• Explain the reason for your appeals for a specific slot

• Assignment teams: you can switch teams from one assignment to another
• You do not need to register your team (for now)

CS3211 L2 - Tasks and Threads 39

You might also like