Skip to content

Commit 4388fec

Browse files
committed
updated mutex lock
1 parent 8f48826 commit 4388fec

File tree

1 file changed

+104
-2
lines changed

1 file changed

+104
-2
lines changed

mutex_lock.ipynb

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
{
22
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
" One Example"
8+
]
9+
},
310
{
411
"cell_type": "markdown",
512
"metadata": {},
@@ -11,7 +18,7 @@
1118
"cell_type": "markdown",
1219
"metadata": {},
1320
"source": [
14-
"illustrates a race condition: Output will vary 10 & 20 each time you run , depending race"
21+
"illustrates a race condition problem: Output will vary 10 & 20 each time you run , depending race"
1522
]
1623
},
1724
{
@@ -62,6 +69,7 @@
6269
"cell_type": "markdown",
6370
"metadata": {},
6471
"source": [
72+
"#### Solution using mutext lock\n",
6573
"#### Using a threading lock to prevent the race condition\n",
6674
"\n",
6775
"In Python, you can use the `Lock` class from the `threading` module to create a lock object:\n",
@@ -195,7 +203,7 @@
195203
"cell_type": "markdown",
196204
"metadata": {},
197205
"source": [
198-
"### Alternative"
206+
"### Alternative (same but reworked code)"
199207
]
200208
},
201209
{
@@ -264,6 +272,100 @@
264272
" # Call the main function to start the threads and perform the synchronization\n",
265273
" main()\n"
266274
]
275+
},
276+
{
277+
"cell_type": "markdown",
278+
"metadata": {},
279+
"source": [
280+
" Another Example"
281+
]
282+
},
283+
{
284+
"cell_type": "markdown",
285+
"metadata": {},
286+
"source": [
287+
"#### Synchronization Errors\n",
288+
"We will create two threads and give each of them a pointer towards a variable in the main containing an unsigned integer, count. Each thread will iterate a certain number of times (defined in the TIMES_TO_COUNT macro) and increment the count at each iteration. Since there are two threads, we will of course expect the final count to be exactly twice TIMES_TO_COUNT."
289+
]
290+
},
291+
{
292+
"cell_type": "markdown",
293+
"metadata": {},
294+
"source": [
295+
"##### Solution using mutext lock"
296+
]
297+
},
298+
{
299+
"cell_type": "code",
300+
"execution_count": null,
301+
"metadata": {},
302+
"outputs": [],
303+
"source": [
304+
"import threading\n",
305+
"import time\n",
306+
"\n",
307+
"# Each thread will count TIMES_TO_COUNT times\n",
308+
"TIMES_TO_COUNT = 21000\n",
309+
"\n",
310+
"class Counter:\n",
311+
" def __init__(self):\n",
312+
" self.count = 0\n",
313+
" self.lock = threading.Lock()\n",
314+
"\n",
315+
" def increment(self):\n",
316+
" with self.lock:\n",
317+
" self.count += 1\n",
318+
"\n",
319+
"def thread_routine(counter):\n",
320+
" # Each thread starts here\n",
321+
" tid = threading.current_thread().ident\n",
322+
" # Print the count before this thread starts iterating.\n",
323+
" # In order to read the value of count, we lock the mutex:\n",
324+
" with counter.lock:\n",
325+
" print(f\"Thread [{tid}]: Count at thread start = {counter.count}\")\n",
326+
" for i in range(TIMES_TO_COUNT):\n",
327+
" # Iterate TIMES_TO_COUNT times\n",
328+
" # Increment the counter at each iteration\n",
329+
" # Lock the mutex for the duration of the incrementation\n",
330+
" counter.increment()\n",
331+
" # Print the final count when this thread finishes its own count,\n",
332+
" # without forgetting to lock the mutex:\n",
333+
" with counter.lock:\n",
334+
" print(f\"Thread [{tid}]: Final count = {counter.count}\")\n",
335+
"\n",
336+
"def main():\n",
337+
" # Structure containing the threads' total count:\n",
338+
" counter = Counter()\n",
339+
"\n",
340+
" # Since each thread counts TIMES_TO_COUNT times and that\n",
341+
" # we have 2 threads, we expect the final count to be\n",
342+
" # 2 * TIMES_TO_COUNT:\n",
343+
" print(f\"Main: Expected count is {2 * TIMES_TO_COUNT}\")\n",
344+
" # Thread creation:\n",
345+
" t1 = threading.Thread(target=thread_routine, args=(counter,))\n",
346+
" print(f\"Main: Created first thread [{t1.ident}]\")\n",
347+
" t2 = threading.Thread(target=thread_routine, args=(counter,))\n",
348+
" print(f\"Main: Created second thread [{t2.ident}]\")\n",
349+
" # Thread starting:\n",
350+
" t1.start()\n",
351+
" t2.start()\n",
352+
" # Thread joining:\n",
353+
" t1.join()\n",
354+
" print(f\"Main: Joined first thread [{t1.ident}]\")\n",
355+
" t2.join()\n",
356+
" print(f\"Main: Joined second thread [{t2.ident}]\")\n",
357+
" # Final count evaluation:\n",
358+
" # (Here we can read the count without worrying about\n",
359+
" # the lock because all threads have been joined and\n",
360+
" # there can be no data race between threads)\n",
361+
" if counter.count != (2 * TIMES_TO_COUNT):\n",
362+
" print(f\"Main: ERROR! Total count is {counter.count}\")\n",
363+
" else:\n",
364+
" print(f\"Main: OK. Total count is {counter.count}\")\n",
365+
"\n",
366+
"if __name__ == \"__main__\":\n",
367+
" main()\n"
368+
]
267369
}
268370
],
269371
"metadata": {

0 commit comments

Comments
 (0)