diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
index 8e818c28e492a9a9fe271607d534b09ae8a87faa..4d7f97378f3eed310208c298f9bf308a6afff164 100644
--- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
+++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
@@ -13,8 +13,10 @@
 
 #include <Poco/Thread.h>
 
+#include <boost/python/arg_from_python.hpp>
 #include <boost/python/bases.hpp>
 #include <boost/python/class.hpp>
+#include <boost/python/dict.hpp>
 #include <boost/python/object.hpp>
 #include <boost/python/operators.hpp>
 #include <boost/python/register_ptr_to_python.hpp>
@@ -30,11 +32,30 @@ using Mantid::PythonInterface::Policies::VectorToNumpy;
 using namespace boost::python;
 
 namespace {
-/***********************************************************************
- *
- * Useful functions within Python to have on the algorithm interface
- *
- ***********************************************************************/
+
+// Global map of the thread ID to the current algorithm object
+dict THREAD_ID_MAP;
+
+/**
+ * Private method to add an algorithm reference to the thread id map.
+ * It replaces any current reference with the same ID
+ * @param threadID The current Python thread ID
+ * @param alg A Python reference to the algorithm object
+ */
+void _trackAlgorithmInThread(long threadID, const object & alg) {
+  THREAD_ID_MAP[threadID] = alg;
+}
+
+/**
+ * Return the algorithm object for the given thread ID or None
+ * if one doesn't exist. The entry is removed from the map
+ * if it is found
+ */
+object _algorithmInThread(long threadID) {
+  auto value = THREAD_ID_MAP.get(threadID);
+  if(value) api::delitem(THREAD_ID_MAP, threadID);
+  return value;
+}
 
 /// Functor for use with sorting algorithm to put the properties that do not
 /// have valid values first
@@ -130,7 +151,6 @@ PyObject *getOutputProperties(IAlgorithm &self) {
   return names;
 }
 
-// ---------------------- Documentation -------------------------------------
 /**
  * Create a doc string for the simple API
  * @param self :: A pointer to the python object wrapping and Algorithm
@@ -176,18 +196,25 @@ std::string createDocString(IAlgorithm &self) {
   return buffer.str();
 }
 
+/**
+ * RAII struct to drop the GIL and reacquire it on destruction.
+ * The algorithm is added to the map of tracked algorithms. See
+ * executeProxy for the reason why
+ */
 struct AllowCThreads {
-  AllowCThreads() : m_tracefunc(NULL), m_tracearg(NULL), m_saved(NULL) {
+  AllowCThreads(const object & algm)
+    : m_tracefunc(NULL), m_tracearg(NULL), m_saved(NULL) {
     PyThreadState *curThreadState = PyThreadState_GET();
-    assert(curThreadState != NULL);
     m_tracefunc = curThreadState->c_tracefunc;
     m_tracearg = curThreadState->c_traceobj;
     Py_XINCREF(m_tracearg);
     PyEval_SetTrace(NULL, NULL);
+    _trackAlgorithmInThread(curThreadState->thread_id, algm);
     m_saved = PyEval_SaveThread();
   }
   ~AllowCThreads() {
     PyEval_RestoreThread(m_saved);
+    api::delitem(THREAD_ID_MAP, m_saved->thread_id);
     PyEval_SetTrace(m_tracefunc, m_tracearg);
     Py_XDECREF(m_tracearg);
   }
@@ -199,22 +226,21 @@ private:
 };
 
 /**
- * Releases the GIL and disables any tracer functions, executes the calling
- *algorithm object
- * and re-acquires the GIL and resets the tracing functions.
- * The trace functions are disabled as they can seriously hamper performance of
- *Python algorithms
- *
- * As an algorithm is a potentially time-consuming operation, this allows other
- *threads
- * to execute python code while this thread is executing C code
+ * Execute the algorithm
  * @param self :: A reference to the calling object
  */
-bool executeWhileReleasingGIL(IAlgorithm &self) {
-  bool result(false);
-  AllowCThreads threadStateHolder;
-  result = self.execute();
-  return result;
+bool executeProxy(object &self) {
+  // We need to do 2 things before we execute the algorthm:
+  //   1. store a reference to this algorithm mapped to the current thread ID to
+  //      allow it to be looked up when an abort request is received
+  //   2. release the GIL, drop the Python threadstate and reset anything installed
+  //      via PyEval_SetTrace while we execute the C++ code - AllowCThreads()
+  //      does this for us
+
+  // Extract this before dropping GIL as I'm not sure if it calls any Python
+  auto & calg = extract<IAlgorithm&>(self)();
+  AllowCThreads threadStateHolder(self);
+  return calg.execute();
 }
 
 /**
@@ -258,8 +284,6 @@ std::string getWikiSummary(IAlgorithm &self) {
 void export_ialgorithm() {
   class_<AlgorithmIDProxy>("AlgorithmID", no_init).def(self == self);
 
-  // --------------------------------- IAlgorithm
-  // ------------------------------------------------
   register_ptr_to_python<boost::shared_ptr<IAlgorithm>>();
 
   class_<IAlgorithm, bases<IPropertyManager>, boost::noncopyable>(
@@ -336,8 +360,11 @@ void export_ialgorithm() {
       .def("initialize", &IAlgorithm::initialize, "Initializes the algorithm")
       .def("validateInputs", &IAlgorithm::validateInputs,
            "Cross-check all inputs and return any errors as a dictionary")
-      .def("execute", &executeWhileReleasingGIL,
+      .def("execute", &executeProxy,
            "Runs the algorithm and returns whether it has been successful")
+      // 'Private' static methods
+      .def("_algorithmInThread", &_algorithmInThread)
+      .staticmethod("_algorithmInThread")
       // Special methods
       .def("__str__", &IAlgorithm::toString)
 
diff --git a/Code/Mantid/MantidPlot/src/PythonScript.cpp b/Code/Mantid/MantidPlot/src/PythonScript.cpp
index 85aae83924fc45f0b47c771b0ba8c0c1f2b854c0..116201f0fe739fac466ed259f2276cf2292fa2d9 100644
--- a/Code/Mantid/MantidPlot/src/PythonScript.cpp
+++ b/Code/Mantid/MantidPlot/src/PythonScript.cpp
@@ -96,6 +96,7 @@ PythonScript::~PythonScript()
   observeADSClear(false);
 
   this->disconnect();
+  Py_XDECREF(m_algorithmInThread);
   Py_XDECREF(localDict);
 }
 
@@ -457,6 +458,10 @@ void PythonScript::initialize(const QString & name, QObject *context)
   GlobalInterpreterLock pythonlock;
   PythonScript::setIdentifier(name);
   setContext(context);
+
+  PyObject *ialgorithm = PyObject_GetAttrString(PyImport_AddModule("mantid.api"), "IAlgorithm");
+  m_algorithmInThread = PyObject_GetAttrString(ialgorithm, "_algorithmInThread");
+  Py_INCREF(m_algorithmInThread);
 }
 
 
@@ -627,8 +632,20 @@ bool PythonScript::executeImpl()
 
 void PythonScript::abortImpl()
 {
+  // The current thread for this script could be
+  // in one of two states:
+  //   1. A C++ algorithm is being executed so it must be
+  //      interrupted using algorithm.cancel()
+  //   2. Pure Python is executing and can be interrupted
+  //      with a KeyboardInterrupt exception
   GlobalInterpreterLock lock;
-  m_pythonEnv->raiseAsyncException(m_threadID, PyExc_KeyboardInterrupt);
+
+  PyObject *curAlg = PyObject_CallFunction(m_algorithmInThread, "l", m_threadID);
+  if(curAlg && curAlg != Py_None){
+    PyObject_CallMethod(curAlg, "cancel", "");
+  } else {
+    m_pythonEnv->raiseAsyncException(m_threadID, PyExc_KeyboardInterrupt);
+  }
 }
 
 void PythonScript::saveThreadID()
diff --git a/Code/Mantid/MantidPlot/src/PythonScript.h b/Code/Mantid/MantidPlot/src/PythonScript.h
index 8f9fe1f4b61b1ecb04feb5614ab6ba4d5660d92b..467572949e71c8ce717455bb44e0f6e82eb84c2e 100644
--- a/Code/Mantid/MantidPlot/src/PythonScript.h
+++ b/Code/Mantid/MantidPlot/src/PythonScript.h
@@ -197,6 +197,8 @@ private:
   PyObject *localDict, *stdoutSave, *stderrSave;
   PyObject *m_codeFileObject;
   long m_threadID; ///< Python thread id
+  /// A reference to the IAlgorithm._algorithmInThread static method
+  PyObject * m_algorithmInThread;
   bool isFunction;
   QString fileName;
   bool m_isInitialized;