diff --git a/gi-gtk-hs.cabal b/gi-gtk-hs.cabal
--- a/gi-gtk-hs.cabal
+++ b/gi-gtk-hs.cabal
@@ -1,5 +1,5 @@
 name:                gi-gtk-hs
-version:             0.3.5.0
+version:             0.3.6.1
 synopsis:            A wrapper for gi-gtk, adding a few more idiomatic API parts on top
 description:         A wrapper for gi-gtk, adding a few more idiomatic API parts on top
 homepage:            https://github.com/haskell-gi/gi-gtk-hs
@@ -18,6 +18,7 @@
 library
   exposed-modules:     Data.GI.Gtk,
                        Data.GI.Gtk.BuildFn
+                       Data.GI.Gtk.Threading
                        Data.GI.Gtk.ModelView.Types
                        Data.GI.Gtk.ModelView.CellLayout
                        Data.GI.Gtk.ModelView.CustomStore
@@ -26,13 +27,13 @@
                        Data.GI.Gtk.ModelView.TreeModel
                        Data.GI.Gtk.ComboBox
 
-  build-depends:       base >=4.7 && <4.11,
-                       base-compat >=0.9.0 && <0.10,
+  build-depends:       base >=4.7 && <5,
+                       base-compat >=0.9.0 && <0.11,
                        mtl >=2.1 && <2.3,
                        transformers >=0.3.0.0 && <0.6,
                        containers >=0.5.5.1 && <0.6,
                        text >=1.2 && <1.3,
-                       haskell-gi-base >=0.20 && <0.21,
+                       haskell-gi-base >=0.20 && <0.22,
                        gi-glib >=2.0.6 && <2.1,
                        gi-gobject >=2.0.6 && <2.1,
                        gi-gdk >=3.0.6 && <3.1,
diff --git a/src/Data/GI/Gtk/Threading.hs b/src/Data/GI/Gtk/Threading.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/GI/Gtk/Threading.hs
@@ -0,0 +1,139 @@
+-- -*-haskell-*-
+--
+-- Author : Brandon Sloane
+--
+-- Created: 16 August 2017
+--
+-- Copyright (C) 2017 Brandon Sloane
+--
+--  This library is free software; you can redistribute it and/or
+--  modify it under the terms of the GNU Lesser General Public
+--  License as published by the Free Software Foundation; either
+--  version 2.1 of the License, or (at your option) any later version.
+--
+--  This library is distributed in the hope that it will be useful,
+--  but WITHOUT ANY WARRANTY; without even the implied warranty of
+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+--  Lesser General Public License for more details.
+--
+-- |
+-- Stability   : provisional
+-- Portability : portable (depends on GHC)
+--
+-- Utility functions for threading
+--
+module Data.GI.Gtk.Threading
+    (
+-- | Utility functions to run IO actions on the GUI thread. You must call
+-- 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread'
+-- before using the synchronous options, or you risk deadlocking.
+--
+-- Note that the notion of "Thread" used by this module corresponds to operating system threads, not Haskell threads.
+-- A single operating system thread may run multiple Haskell threads, and a Haskell thread may migrate between operating system threads.
+-- In order for this nothing of "Thread" to make sense to a Haskell program, we must be working in a bound Haskell thread, which is tied to a single operating system thread.
+-- Haskell's main function is automatically bound, and the postGUI functions will create a new bound thread if nessasary.
+      setGUIThread
+    , getGUIThread
+    , setCurrentThreadAsGUIThread
+    , postGUISyncWithPriority
+    , postGUISync
+    , postGUIASyncWithPriority
+    , postGUIASync
+    , compareThreads
+    , isGUIThread
+    , module GI.GLib --threadSelf and Thread
+    ) where
+
+import Control.Concurrent
+import Control.Concurrent.MVar
+import Data.Int (Int32)
+import System.IO.Unsafe (unsafePerformIO)
+import System.IO (stderr, hPutStrLn)
+import GI.Gdk (threadsAddIdle)
+import GI.GLib.Constants
+import GI.GLib (threadSelf, Thread(..))
+import Data.GI.Base.ManagedPtr
+
+
+guiThread :: MVar (Maybe Thread)
+{-# NOINLINE guiThread #-}
+guiThread = unsafePerformIO $ newMVar Nothing
+
+-- | Inform gi-gtk-hs what thread is running the gtk main loop.
+setGUIThread :: Thread -> IO ()
+setGUIThread t = swapMVar guiThread (Just t) >> return ()
+
+-- | Inform gi-gtk-hs that the current thread is, or will be, running the gtk main loop.
+--
+-- Equivalent to @'GI.GLib.threadSelf' >>= 'Data.GI.Gtk.Threading.setGUIThread'@
+setCurrentThreadAsGUIThread :: IO ()
+setCurrentThreadAsGUIThread = threadSelf >>= setGUIThread
+
+-- | Get the Thread that is running the Gtk main loop, if it has been set.
+getGUIThread :: IO (Maybe Thread)
+getGUIThread = readMVar guiThread
+
+-- | Queue an action to be run in the GTK event loop.
+-- If called from the same process as the event loop, this runs the action directly.
+-- Otherwise, this queues it in GTK's event loop and blocks until the action is complete
+--
+-- You must call 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread' before this.
+--
+-- Priority is typically between 'GI.GLib.Constants.PRIORITY_HIGH_IDLE' (100) and 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE' (200)
+postGUISyncWithPriority :: Int32 -> IO a -> IO a
+postGUISyncWithPriority priority action = runInBoundThread $ do
+    b <- isGUIThread
+    if b then
+        action
+    else
+        run
+    where
+    run = do
+        ans <- newEmptyMVar
+        threadsAddIdle priority $ action >>= putMVar ans >> return False
+        takeMVar ans
+
+-- | Queue an action to be run in the GTK event loop.
+-- If called from the same process as the event loop, this runs the action directly.
+-- Otherwise, this queues it in GTK's event loop and blocks until the action is complete
+--
+-- You must call 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread' before this.
+--
+-- Equivalent to @'Data.GI.Gtk.Threading.postGUISyncWithPriority' 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE'@
+postGUISync :: IO a -> IO a
+postGUISync = postGUISyncWithPriority PRIORITY_DEFAULT_IDLE
+
+-- | Queue an action to be run in the GTK event loop.
+-- This function queues the event regardless of what process it is called from, and returns immidietly.
+--
+-- Priority is typically between 'GI.GLib.Constants.PRIORITY_HIGH_IDLE' (100) and 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE' (200)
+postGUIASyncWithPriority :: Int32 -> IO () -> IO ()
+postGUIASyncWithPriority priority action = threadsAddIdle priority (action >> return False) >> return ()
+
+-- | Queue an action to be run in the GTK event loop.
+-- This function queues the event regardless of what process it is called from, and returns immidietly.
+--
+-- Equivalent to @'Data.GI.Gtk.Threading.postGUIASyncWithPriority' 'GI.GLib.Constants.PRIORITY_DEFAULT_IDLE'@
+postGUIASync :: IO () -> IO ()
+postGUIASync = postGUIASyncWithPriority PRIORITY_DEFAULT_IDLE
+
+-- | Test if two 'GI.GLib.Structs.Thread.Thread's refer to the same OS thread.
+-- A 'GI.GLib.Structs.Thread.Thread' can be gotten from 'GI.GLib.Structs.Thread.threadSelf'.
+-- Note that 'GI.GLib.Structs.Thread.threadSelf' only makes sense from a bound thread.
+compareThreads :: Thread -> Thread -> IO Bool
+compareThreads (Thread mptr1) (Thread mptr2) =
+    withManagedPtr mptr1 $ \ptr1 ->
+    withManagedPtr mptr2 $ \ptr2 ->
+    return $ ptr1 == ptr2
+
+-- | Check if the current thread is the Gtk gui thread.
+--
+-- You must call 'Data.GI.Gtk.Threading.setGUIThread' or 'Data.GI.Gtk.Threading.setCurrentThreadAsGUIThread' before this.
+-- This only makes sense when called from a bound thread.
+isGUIThread :: IO Bool
+isGUIThread = do
+    guiThread <- getGUIThread
+    case guiThread of
+        Nothing -> hPutStrLn stderr "WARNING Data.GI.Gtk.Threading Calling isGUIThread before setGUIThread" >> return False
+        Just t1 -> threadSelf >>= compareThreads t1
+
