diff --git a/prboom2/CMakeLists.txt b/prboom2/CMakeLists.txt
index d317ddec..c86f76b0 100644
--- a/prboom2/CMakeLists.txt
+++ b/prboom2/CMakeLists.txt
@@ -53,6 +53,15 @@ endif()
 check_symbol_exists(getopt "unistd.h" HAVE_GETOPT)
 check_symbol_exists(mmap "sys/mman.h" HAVE_MMAP)
 check_symbol_exists(CreateFileMapping "windows.h" HAVE_CREATE_FILE_MAPPING)
+if(NOT WIN32)
+    set(CMAKE_REQUIRED_DEFINITIONS_PREV ${CMAKE_REQUIRED_DEFINITIONS})
+    set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_GNU_SOURCE)
+    check_symbol_exists(sched_setaffinity "sched.h" HAVE_SCHED_SETAFFINITY)
+    set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS_PREV})
+    if(HAVE_SCHED_SETAFFINITY)
+        add_definitions(-D_GNU_SOURCE)
+    endif()
+endif()
 check_symbol_exists(strsignal "string.h" HAVE_STRSIGNAL)
 check_symbol_exists(mkstemp "stdlib.h" HAVE_MKSTEMP)
 
diff --git a/prboom2/cmake/config.h.cin b/prboom2/cmake/config.h.cin
index f92f3d88..2ad70033 100644
--- a/prboom2/cmake/config.h.cin
+++ b/prboom2/cmake/config.h.cin
@@ -11,6 +11,7 @@
 #cmakedefine HAVE_GETOPT
 #cmakedefine HAVE_MMAP
 #cmakedefine HAVE_CREATE_FILE_MAPPING
+#cmakedefine HAVE_SCHED_SETAFFINITY
 #cmakedefine HAVE_STRSIGNAL
 #cmakedefine HAVE_MKSTEMP
 
diff --git a/prboom2/src/SDL/i_main.c b/prboom2/src/SDL/i_main.c
index 7537c53f..670f3dbd 100644
--- a/prboom2/src/SDL/i_main.c
+++ b/prboom2/src/SDL/i_main.c
@@ -45,6 +45,9 @@
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+typedef BOOL (WINAPI *SetAffinityFunc)(HANDLE hProcess, DWORD mask);
+#else
+#include <sched.h>
 #endif
 
 #include <errno.h>
@@ -373,6 +376,83 @@ static void I_Quit (void)
 uid_t stored_euid = -1;
 #endif
 
+//
+// Ability to use only the allowed CPUs
+//
+
+static void I_SetAffinityMask(void)
+{
+  // This was only set for the sdl music backend,
+  //   but now the backend changes based on the music type.
+  // Not sure what the consequences are for this...
+  process_affinity_mask = 1;
+
+  // Set the process affinity mask so that all threads
+  // run on the same processor.  This is a workaround for a bug in
+  // SDL_mixer that causes occasional crashes.
+  if (process_affinity_mask)
+  {
+    const char *errbuf = NULL;
+#ifdef _WIN32
+    HMODULE kernel32_dll;
+    SetAffinityFunc SetAffinity = NULL;
+    int ok = false;
+
+    // Find the kernel interface DLL.
+    kernel32_dll = LoadLibrary("kernel32.dll");
+
+    if (kernel32_dll)
+    {
+      // Find the SetProcessAffinityMask function.
+      SetAffinity = (SetAffinityFunc)GetProcAddress(kernel32_dll, "SetProcessAffinityMask");
+
+      // If the function was not found, we are on an old (Win9x) system
+      // that doesn't have this function.  That's no problem, because
+      // those systems don't support SMP anyway.
+
+      if (SetAffinity)
+      {
+        ok = SetAffinity(GetCurrentProcess(), process_affinity_mask);
+      }
+    }
+
+    if (!ok)
+    {
+      errbuf = WINError();
+    }
+#elif defined(HAVE_SCHED_SETAFFINITY)
+    // POSIX version:
+    int i;
+    {
+      cpu_set_t set;
+
+      CPU_ZERO(&set);
+
+      for(i = 0; i < 16; i++)
+      {
+        CPU_SET((process_affinity_mask>>i)&1, &set);
+      }
+
+      if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
+      {
+        errbuf = strerror(errno);
+      }
+    }
+#else
+    return;
+#endif
+
+    if (errbuf == NULL)
+    {
+      lprintf(LO_INFO, "I_SetAffinityMask: manual affinity mask is %d\n", process_affinity_mask);
+    }
+    else
+    {
+      lprintf(LO_ERROR, "I_SetAffinityMask: failed to set process affinity mask (%s)\n", errbuf);
+    }
+  }
+}
+
 //
 // Sets the priority class for the prboom-plus process
 //
@@ -482,6 +562,9 @@ int main(int argc, char **argv)
   signal(SIGABRT, I_SignalHandler);
 #endif
 
+  // Ability to use only the allowed CPUs
+  I_SetAffinityMask();
+
   // Priority class for the prboom-plus process
   I_SetProcessPriority();
 
diff --git a/prboom2/src/SDL/i_video.c b/prboom2/src/SDL/i_video.c
index 5a564a5a..9b68aee7 100644
--- a/prboom2/src/SDL/i_video.c
+++ b/prboom2/src/SDL/i_video.c
@@ -895,6 +895,7 @@ static void I_ClosestResolution (int *width, int *height)
   }
 }
 
+int process_affinity_mask;
 int process_priority;
 
 // e6y
diff --git a/prboom2/src/i_video.h b/prboom2/src/i_video.h
index 46f0fb71..c39a197e 100644
--- a/prboom2/src/i_video.h
+++ b/prboom2/src/i_video.h
@@ -109,6 +109,8 @@ void I_UpdateRenderSize(void);	// Handle potential
 extern int renderW;		// resolution scaling
 extern int renderH;		// - DTIED
 
+// Set the process affinity mask so that all threads
+extern int process_affinity_mask;
 // Priority class for the prboom-plus process
 extern int process_priority;
 // Use vanilla keybaord mapping
