Multi-threaded architecture

As I am looking to add elements of multi-threaded features to the RSS reader that I am developing, I have been researching into multi-threaded architectures and basically what concurrency is. After the jump I will explain in detail what multi-threaded is and how they can be incorporated into an application, and I hope if your a beginner like me when it comes to multi-threading, you will understand it better afterwards too.

My projects and what if I had incorporated multi-threaded design? Most of the applications that I have developed in the past have been sequential programs and therefore lacked the real-time edge that multi-threaded applications give us today. For example the Newsreader application which I developed in c++ for my undergraduate degree was only a sequential program. It therefore, did not allow a user to carry out multiple tasks at one time. Say for example if the user downloaded newsgroups from the NNTP server, they would have had to wait until that process was complete in order to start another function in the application such as read an article in a newsgroup. This meant that the application would lock out user input whilst a task was running and then re-enable itself once the task had completed. Looking back I now understand that this type of application would have been better if it was multi-threaded thus allowing a user to carry out multiple processes simultaneously. Therefore, before we start talking about multi-threaded design that it is not needed in all applications and in many occasions multi-threading can cause a lot of headaches for a developer (I will discuss the problems later on in this post).

What is a process and a thread?

Process

A running application. For example when you launch notepad from Windows this in essence is a process executed.

Thread

Unit which the operating system allocates processor time. A thread can execute any parts of code of the process - including parts of currently being executed by another thread.

Sequential Vs Multi-threaded applications

Sequential

  • Can only utilize single processor
  • Behaviour is deterministic
  • Testing can discover most bugs
  • Once bug is discovered fix is generally assured

Multi-threaded programs

  • Takes advantage of multi-processor hardware
  • Behaviour is non-deterministic
  • Threads racing to access memory causes problematic bugs
  • Root causes found by assuming a race (explained later) fits behaviour + reviewing code

Programming in sequential and multi-threaded programs:

Sequential

  • Memory stable unless explicitly updated
  • No locks are needed
  • Data structure invariants need to hold on entry and exit of the data sttuctures methods
  • No special considerations when accessing 2 interdependent data structures
  • Deadlock can’t happen

Multi-threaded programs

  • Memory is changing unless read-only, thread local or protected by a lock
  • Locks essential
  • Data structures invariants have to hold any time the lock protecting the data structure is not held
  • 2 data structures are related - locks for both structures must be enabled before using relationship
  • Deadlock possible when multiple unordered locks

Thread and Memory

  • Multi-threaded programming: instead of having one processing unit doing work sequentially you have 2 / more executing simultaneously.

  • Tricky part of multi-threading programming is how threads communicate with each other.

Shared Memory Threading Model:

Common Memory————————–> Thread 1 ————————–> Thread 2 ————————–> Thread N

[Memory interleaves requests from all threads]

  • In this model all threads have access to the same pool of shared memory.
  • Does not distinguish between memory that is being used strictly for thread local use (most declared variables) and memory that is used to communicate with other threads (global variables and heap memory)

Races

  • Imagine a program that processes requests and has a global counter - totalRequests - incremented as request completed

e.g. totalRequests = totalRequests +1;

BUT

  • Program has multiple threads servicing requests and updating totalRequests = PROBLEM
  • Problem if two threads ran this code simultaneously

Locks [Monitor / Mutex / Critical section / binary semaphore]

  • Most common way of preventing races.
  • Prevents other threads from accessing memory associated with an invariant while it is broken.
  • Locks are often called monitor / critical section / mutex / binary sempahore
  • Provides mechanism for ensuring that only 1 thread can execute a particular region of code at any given time
  • .Net Framework locks are implemented by System.Threading.Monitor class.
  • Provides Enter and Exit methods

-Enter

  • when a thread calls Enter all attempts by other threads to call Enter will cause other threads to block WAIT until a call to Exit is made.

  • The thread that calls Enter is the owner of the lock

Lock example:

static object totalRequestsLock = new Object();

     System.Threading.Monitor.Enter(totalRequestsLock);
     totalRequests = totalRequests +1;
     System.Threading.Monitor.Exit(totalRequestsLock);

Deadlock

  • Once a program has more than 1 lock deadlock becomes a possibility.
  • Happens when two threads are waiting for a mutex owned by the other.
  • Deadlock occurs when some threads are blocked to acquire resources held by other blocked threads.

Scenario:

  • when 2 threads each hold a monitor (mutex,lock..) that the other one wants.
  • each blocks waiting for the mutex thats its waiting for to be released and so the mutex are never released
Last updated on 1 Jun 2009
Published on 1 Jun 2009