diff --git a/advanced_topics/07_threading.ipynb b/advanced_topics/07_threading.ipynb
index e8a1a36688775ebd745dfc791d472202eda0cf42..9bf762639b61832ee23f3863811aec73bbbee79b 100644
--- a/advanced_topics/07_threading.ipynb
+++ b/advanced_topics/07_threading.ipynb
@@ -28,20 +28,20 @@
     "\n",
     "\n",
     "* [Threading](#threading)\n",
-    " * [Subclassing `Thread`](#subclassing-thread)\n",
-    " * [Daemon threads](#daemon-threads)\n",
-    " * [Thread synchronisation](#thread-synchronisation)\n",
-    "   * [`Lock`](#lock)\n",
-    "   * [`Event`](#event)\n",
-    " * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil)\n",
+    "  * [Subclassing `Thread`](#subclassing-thread)\n",
+    "  * [Daemon threads](#daemon-threads)\n",
+    "  * [Thread synchronisation](#thread-synchronisation)\n",
+    "    * [`Lock`](#lock)\n",
+    "    * [`Event`](#event)\n",
+    "  * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil)\n",
     "* [Multiprocessing](#multiprocessing)\n",
-    " * [`threading`-equivalent API](#threading-equivalent-api)\n",
-    " * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool)\n",
-    "   * [`Pool.map`](#pool-map)\n",
-    "   * [`Pool.apply_async`](#pool-apply-async)\n",
+    "  * [`threading`-equivalent API](#threading-equivalent-api)\n",
+    "  * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool)\n",
+    "    * [`Pool.map`](#pool-map)\n",
+    "    * [`Pool.apply_async`](#pool-apply-async)\n",
     "* [Sharing data between processes](#sharing-data-between-processes)\n",
-    " * [Read-only sharing](#read-only-sharing)\n",
-    " * [Read/write sharing](#read-write-sharing)\n",
+    "  * [Read-only sharing](#read-only-sharing)\n",
+    "  * [Read/write sharing](#read-write-sharing)\n",
     "\n",
     "\n",
     "<a class=\"anchor\" id=\"threading\"></a>\n",
@@ -732,8 +732,8 @@
     "\n",
     "\n",
     "Let's see this in action with a simple example. We'll start by defining a\n",
-    "little helper function which allows us to track the total memory usage, using\n",
-    "the unix `free` command:"
+    "horrible little helper function which allows us to track the total memory\n",
+    "usage:"
    ]
   },
   {
@@ -742,14 +742,24 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# todo mac version\n",
+    "import sys\n",
     "import subprocess as sp\n",
     "def memusage(msg):\n",
-    "    stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode()\n",
-    "    stdout = stdout.split('\\n')[1].split()\n",
-    "    total  = stdout[1]\n",
-    "    used   = stdout[2]\n",
-    "    print('Memory usage {}: {} / {} MB'.format(msg, used, total))"
+    "    if sys.platform == 'darwin':\n",
+    "        total = sp.run(['sysctl', 'hw.memsize'], capture_output=True).stdout.decode()\n",
+    "        total = int(total.split()[1]) // 1048576\n",
+    "        usage = sp.run('vm_stat', capture_output=True).stdout.decode()\n",
+    "        usage = usage.strip().split('\\n')\n",
+    "        usage = [l.split(':') for l in usage]\n",
+    "        usage = {k.strip() : v.strip() for k, v in usage}\n",
+    "        usage = int(usage['Pages free'][:-1]) / 256.0\n",
+    "        usage = int(total - usage)\n",
+    "    else:\n",
+    "        stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode()\n",
+    "        stdout = stdout.split('\\n')[1].split()\n",
+    "        total  = int(stdout[1])\n",
+    "        usage  = int(stdout[2])\n",
+    "    print('Memory usage {}: {} / {} MB'.format(msg, usage, total))"
    ]
   },
   {
@@ -823,8 +833,8 @@
     "data? Go back to the code block above and:\n",
     "\n",
     "1. Modify the `process_chunk` function so that it modifies every element of\n",
-    "   its assigned portion of the data before calculating and returning the sum.\n",
-    "   For example:\n",
+    "   its assigned portion of the data before the call to `time.sleep`.  For\n",
+    "   example:\n",
     "\n",
     "   > ```\n",
     "   > data[offset:offset + nelems] += 1\n",
diff --git a/advanced_topics/07_threading.md b/advanced_topics/07_threading.md
index 2c09234d29527148586a09133d28a437077dac47..14b89e782aad06a93858d39119acdbb47aa8b46b 100644
--- a/advanced_topics/07_threading.md
+++ b/advanced_topics/07_threading.md
@@ -22,20 +22,20 @@ module.  If you want to be impressed, skip straight to the section on
 
 
 * [Threading](#threading)
- * [Subclassing `Thread`](#subclassing-thread)
- * [Daemon threads](#daemon-threads)
- * [Thread synchronisation](#thread-synchronisation)
-   * [`Lock`](#lock)
-   * [`Event`](#event)
- * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil)
+  * [Subclassing `Thread`](#subclassing-thread)
+  * [Daemon threads](#daemon-threads)
+  * [Thread synchronisation](#thread-synchronisation)
+    * [`Lock`](#lock)
+    * [`Event`](#event)
+  * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil)
 * [Multiprocessing](#multiprocessing)
- * [`threading`-equivalent API](#threading-equivalent-api)
- * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool)
-   * [`Pool.map`](#pool-map)
-   * [`Pool.apply_async`](#pool-apply-async)
+  * [`threading`-equivalent API](#threading-equivalent-api)
+  * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool)
+    * [`Pool.map`](#pool-map)
+    * [`Pool.apply_async`](#pool-apply-async)
 * [Sharing data between processes](#sharing-data-between-processes)
- * [Read-only sharing](#read-only-sharing)
- * [Read/write sharing](#read-write-sharing)
+  * [Read-only sharing](#read-only-sharing)
+  * [Read/write sharing](#read-write-sharing)
 
 
 <a class="anchor" id="threading"></a>
@@ -638,19 +638,29 @@ any copying required.
 
 
 Let's see this in action with a simple example. We'll start by defining a
-little helper function which allows us to track the total memory usage, using
-the unix `free` command:
+horrible little helper function which allows us to track the total memory
+usage:
 
 
 ```
-# todo mac version
+import sys
 import subprocess as sp
 def memusage(msg):
-    stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode()
-    stdout = stdout.split('\n')[1].split()
-    total  = stdout[1]
-    used   = stdout[2]
-    print('Memory usage {}: {} / {} MB'.format(msg, used, total))
+    if sys.platform == 'darwin':
+        total = sp.run(['sysctl', 'hw.memsize'], capture_output=True).stdout.decode()
+        total = int(total.split()[1]) // 1048576
+        usage = sp.run('vm_stat', capture_output=True).stdout.decode()
+        usage = usage.strip().split('\n')
+        usage = [l.split(':') for l in usage]
+        usage = {k.strip() : v.strip() for k, v in usage}
+        usage = int(usage['Pages free'][:-1]) / 256.0
+        usage = int(total - usage)
+    else:
+        stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode()
+        stdout = stdout.split('\n')[1].split()
+        total  = int(stdout[1])
+        usage  = int(stdout[2])
+    print('Memory usage {}: {} / {} MB'.format(msg, usage, total))
 ```
 
 
@@ -713,8 +723,8 @@ your data. But what if your worker processes need to be able to modify the
 data? Go back to the code block above and:
 
 1. Modify the `process_chunk` function so that it modifies every element of
-   its assigned portion of the data before calculating and returning the sum.
-   For example:
+   its assigned portion of the data before the call to `time.sleep`.  For
+   example:
 
    > ```
    > data[offset:offset + nelems] += 1