Drinking Game Threads Project

This project is about the process of implement the 'Starting gun' and 'Shutting down' logic for detached threads.

Software Used  

Languages Used  

Visual Studio

C++

Feel Free to Download the Source Code.
Source Code

Project Topics

Explanations
Synchronization
Deadlocks
Thread Types
Mutex
Condition Variables
Synchronization Primitives
Deadlocks







Objectives

image

When dealing with threads and the need to access multiple mutex-protected resources, there is the possibility for “deadlock” to occur. Deadlock (sometimes called “deadly embrace”) is a situation where two or more competing actions are waiting for the other to finish, and thus neither ever does. To illustrate this, we are going to write code to run a drinking game.

Programming Code

Guidance

Usage: DrinkingGame drinkerCount bottleCount openerCount
           
Arguments:
                      drinker Count                           Number of drinkers.
                      bottle Count                             Number of bottles.
                      opener Count                           Number of openers.
         

The drinking game consists of Drinkers, Bottles, and Bottle Openers. During the gameplay drinkers will be constantly trying to drink, which consists of acquiring a bottle and an opener resource. Once a drinker is able to successfully acquire both resources it will  take a drink, sleep for a while, then release both resources so another drinker can use them.

When trying to get the resources one of two things may happen: the drinker acquires both resources or the drinker fails to get any resources. Each resource has a mutex that determines if it's currently in use - if it's locked then it's being used by a drinker. The drinker will randomly pick a bottle or an opener as its first resource and lock it. Once the drinker has the first resource it will need to look through the entire pool of resources for the second resource. If the drinker had a bottle as the first resource then it will need to look for an unused opener. It is possible that the          drinker cannot find the second resource - in this case the drinker has failed to get both resources.

Programming Explanation

Synchronization

Insure that events in multiple threads always occur in the
correct  order
Allow the safe sharing of data between threads
Beware of overuse of synchronization

Thread Types

Joinable – All spawned threads begin as joinable, they need to be declared
as detached or Joined.  Once declared they can not be changed.


Joined – A thread that has been declared as joined has a relationship with
the thread that contains the join. The thread with the join will wait at the
place where the join appears for the joined thread to complete before
moving on


Detached - Detached threads are mostly independent of the thread that
spawns them

If you omit this call, the result is undefined

Threads may be scheduled by the system scheduler (OS) or by a scheduler in the thread library (depending on the threading model).  

The scheduler in the thread library:

>will preempt currently running threads on the basis of priority
>does NOT time-slice (i.e., is not fair).  A running thread will continue to run forever unless:
o a thread call is made into the thread library
o a blocking call is made
o the running thread calls sched_yield()

Managing Dependencies and Protecting Critical Sections

Mutexes
Condition Variables
Reader/Writer Locks
Semaphores
Barriers

A Mutex (Mutual Exclusion) is a data element that allowsmultiple threads to synchronize their access to sharedresources. It is a lockable object that is designed tosignal when critical sections of code need exclusiveaccess, preventing other threads with the sameprotection from executing concurrently and access thesame memory locations.
Like a binary semaphore, a mutex has two states, locked and unlocked

Only one thread can lock a mutex
Once a mutex is locked, other threads will block when they try to lock the same mutex, until the locking mutex unlocks the mutex, at which point one of the waiting thread’s lock will succeed, and the process begins again

Condition Variables

A Condition variable is synchronization mechanism that
allows multiple threads to conditionally wait, until some
defined time at which they can proceed.
Condition variables are different from mutexes because
they don’t protect code, but procedure.
A thread will wait on a condition variable until the
variable signals it can proceed.


Synchronization Primitives

Counting Semaphores
• Permit a limited number of threads to execute a section of the code
Binary Semaphores - Mutexes
• Permit only one thread to execute a section of the code
Condition Variables
• Communicate information about the state of shared data

Deadlocks

When two or more competing processes are waiting for each other to release resources, and neither do

Deadlock Characterization
Mutual exclusion:  only one process at a time can use a resource
Hold and wait:  a process holding at least one resource is waiting to
acquire additional resources held by other processes
No preemption:  a resource can be released only voluntarily by the
process holding it, after that process has completed its task
Circular wait:  there exists a set {P0, P1, ..., Pn} of waiting processes
such that P0 is waiting for a resource that is held by P1, P1 is waiting for
a resource that is held by P2, ..., Pn–1 is waiting for a resource that is
held by Pn, and Pn is waiting for a resource that is held by P0.