Commit 628a1627 authored by MoutazDebbaneh's avatar MoutazDebbaneh

Add README.MD, Typo fix

parent 52d97608
# Concurrent Sorted Linked List
# Concurrent Sorted Linked List HW - Moutaz Debbaneh
## Introduction
We try to implement a concurrent sorted linked list in different manners to get thread-safe and suitable performance on this data structure.
## Notes
1. Maintaining the length of the list was implemented using a class variable that gets edited upon successful add/remove
operations. This way, getting the length is done in O(1).
2. The number of successful/unsuccessful operations was also implemented in a similar way.
3. All results matched except for the results of unsuccessful contains. The is because we are using a read lock while
writing to a shared-memory variable. To fix this without making the function much slower, two new locks were made for accessing the variables representing the number of successful/unsuccessful contains. This way, the results all matches and the RWLock contains method is still much faster than other implementations.
4. The execution times below might be a little slower than expected because the tests are run while the laptop is on
battery in power saving mode.
## Content
* Data Race.
* Mutual Exclusion.
* Structured Lock (synchronized).
* Unstructured Lock (ReentrantLock, ReentrantReadWriteLock).
* Test different implementations' performance.
---
## TO-DO
* Test throughput (operations per second) for different Sorted Linked List Implementations.
## Results
> Number of cores on laptop = 8
>
> randNumsRange = 80,000
- ### Test #1
| numOfThreads = 8 </br> randNumsLength = 20,000 | **SyncList** | **LockList** | **RWLockList** |
|:----------------------------------------------:|:------------:|:------------:|:--------------:|
| _Add Exc Time_ | 1677 ms | 3634 ms | 3717 ms |
| _Length After Add_ | 17761 | 17761 | 17761 |
| _Contain Exec Time_ | 3874 ms | 7905 ms | 553 ms |
| _Successful/Unsuccessful Contain_ | 4404 / 15596 | 4404 / 15596 | 4404 / 15596 |
| _Remove Exec Time_ | 3429 ms | 6370 ms | 6402 ms |
| _Length After Remove_ | 13864 | 13864 | 13864 |
| _Successful/Unsuccessful Remove_ | 3897 / 16103 | 3897 / 16103 | 3897 / 16103 |
---
- ### Test #2
| numOfThreads = 20 </br> randNumsLength = 20,000 | **SyncList** | **LockList** | **RWLockList** |
|:-----------------------------------------------:|:------------:|:------------:|:--------------:|
| _Add Exc Time_ | 1823 ms | 1523 ms | 4013 ms |
| _Length After Add_ | 17761 | 17761 | 17761 |
| _Contain Exec Time_ | 4420 ms | 4546 ms | 1539 ms |
| _Successful/Unsuccessful Contain_ | 4404 / 15596 | 4404 / 15596 | 4404 / 15596 |
| _Remove Exec Time_ | 3359 ms | 3723 ms | 6751 ms |
| _Length After Remove_ | 13864 | 13864 | 13864 |
| _Successful/Unsuccessful Remove_ | 3897 / 16103 | 3897 / 16103 | 3897 / 16103 |
- ### Test #3
| numOfThreads = 8 </br> randNumsLength = 40,000 | **SyncList** | **LockList** | **RWLockList** |
|:----------------------------------------------:|:-------------:|:-------------:|:--------------:|
| _Add Exc Time_ | 8455 ms | 12090 ms | 13139 ms |
| _Length After Add_ | 31430 | 31430 | 31430 |
| _Contain Exec Time_ | 14448 ms | 3823 ms | 1894 ms |
| _Successful/Unsuccessful Contain_ | 15467 / 24533 | 15467 / 24533 | 15467 / 24533 |
| _Remove Exec Time_ | 11694 ms | 3792 ms | 18928 ms |
| _Length After Remove_ | 19100 | 19100 | 19100 |
| _Successful/Unsuccessful Remove_ | 12330 / 27670 | 12330 / 27670 | 12330 / 27670 |
---
## Bonus Question Implementation & Results
- The main idea is to define a lock on each Entry (RWLock).
- We define a new method safeRemoveElement() that deletes one element making use of the entries locks.
- We also define a new method removeList() that applies the above method on each element.
- While navigating the list, we maintain a readLock on the curr and prev entries.
- When we jump to the next node we unlock the elements we don't need anymore and lock the new node.
- When we reach the potential position of the element we want to remove we use writeLock instead of readLock.
- The execution time using this implementation was significantly better than the old one (~ 5000ms difference)
| numOfThreads = 8 </br> randNumsLength = 20,000 | **RWLockList** |
|:----------------------------------------------:|:--------------:|
| _Add Exc Time_ | 2922 ms |
| _Length After Add_ | 17761 |
| _Contain Exec Time_ | 610 ms |
| _Successful/Unsuccessful Contain_ | 4404 / 15596 |
| **_Remove All Exec Time_** | **1156 ms** |
| _Length After Remove_ | 13864 |
| _Successful/Unsuccessful Remove_ | 3897 / 16103 |
\ No newline at end of file
......@@ -32,9 +32,10 @@ public class SyncListTest extends TestCase {
int randLength = 20_000;
int numOfThreads = 8;
int randNumsRange = 80_000;
int setSeed = 0;
public void testHelp(SortList sortList, String label) {
RandomSequenceGenerator randomSeq = new RandomSequenceGenerator(0, randNumsRange);
RandomSequenceGenerator randomSeq = new RandomSequenceGenerator(setSeed, randNumsRange);
List<Thread> addThreads = new ArrayList<Thread>();
List<Thread> containThreads = new ArrayList<Thread>();
......@@ -120,7 +121,7 @@ public class SyncListTest extends TestCase {
public void testWithRemoveAllHelp(RWLockList sortList, String label) {
RandomSequenceGenerator randomSeq = new RandomSequenceGenerator(0, randNumsRange);
RandomSequenceGenerator randomSeq = new RandomSequenceGenerator(setSeed, randNumsRange);
List<Thread> addThreads = new ArrayList<Thread>();
List<Thread> containThreads = new ArrayList<Thread>();
......@@ -201,7 +202,7 @@ public class SyncListTest extends TestCase {
testHelp(syncList, "Synchronized");
System.out.println("\n**********************************************************\n");
testHelp(lockList, "Locked");
testHelp(lockList, "Lock");
System.out.println("\n**********************************************************\n");
testHelp(rwLockList, "RWLockList");
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment