diff --git a/.travis.yml b/.travis.yml
index 4f4303f..0f25d2d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,9 @@ before_install:
   - git clone https://github.com/Axelrod-Python/TourExec.git /tmp/TourExec
   - cd /tmp/TourExec
   - sudo make install
-  - export LD_LIBRARY_PATH=/usr/local/lib
+  - echo "/usr/lib/libstrategies.so" | sudo tee /etc/ld.so.conf.d/strategies-lib.conf
+  - sudo ldconfig
+  - ldconfig -p | grep libstrategies.so
   - cd $TRAVIS_BUILD_DIR
 install:
   - pip install -r requirements.txt
diff --git a/src/axelrod_fortran/player.py b/src/axelrod_fortran/player.py
index 2237c11..19198a7 100644
--- a/src/axelrod_fortran/player.py
+++ b/src/axelrod_fortran/player.py
@@ -1,23 +1,37 @@
+from ctypes import byref, c_float, c_int, POINTER
 import random
 import warnings
 
 import axelrod as axl
 from axelrod.interaction_utils import compute_final_score
 from axelrod.action import Action
-from ctypes import cdll, c_int, c_float, byref, POINTER
+
 from .strategies import characteristics
+from .shared_library_manager import MultiprocessManager, load_library
 
 C, D = Action.C, Action.D
 actions = {0: C, 1: D}
 original_actions = {C: 0, D: 1}
 
 
+self_interaction_message = """
+You are playing a match with the same player against itself. However
+axelrod_fortran players share memory. You can initialise another instance of an
+Axelrod_fortran player with player.clone().
+"""
+
+
+# Initialize a module-wide manager for loading copies of the shared library.
+manager = MultiprocessManager()
+manager.start()
+shared_library_manager = manager.SharedLibraryManager("libstrategies.so")
+
+
 class Player(axl.Player):
 
     classifier = {"stochastic": True}
 
-    def __init__(self, original_name,
-                 shared_library_name='libstrategies.so'):
+    def __init__(self, original_name):
         """
         Parameters
         ----------
@@ -28,14 +42,16 @@ def __init__(self, original_name,
             A instance of an axelrod Game
         """
         super().__init__()
-        self.shared_library_name = shared_library_name
-        self.shared_library = cdll.LoadLibrary(shared_library_name)
+        self.index, self.shared_library_filename = \
+            shared_library_manager.get_filename_for_player(original_name)
+        self.shared_library = load_library(self.shared_library_filename)
         self.original_name = original_name
         self.original_function = self.original_name
         is_stochastic = characteristics[self.original_name]['stochastic']
         if is_stochastic is not None:
             self.classifier['stochastic'] = is_stochastic
 
+
     def __enter__(self):
         return self
 
@@ -75,17 +91,8 @@ def original_strategy(
         return self.original_function(*[byref(arg) for arg in args])
 
     def strategy(self, opponent):
-        if type(opponent) is Player \
-          and (opponent.original_name == self.original_name) \
-          and (opponent.shared_library_name == self.shared_library_name):
-
-            message = """
-You are playing a match with two copies of the same player.
-However the axelrod fortran players share memory.
-You can initialise an instance of an Axelrod_fortran player with a
-`shared_library_name`
-variable that points to a copy of the shared library."""
-            warnings.warn(message=message)
+        if self is opponent:
+            warnings.warn(message=self_interaction_message)
 
         if not self.history:
             their_last_move = 0
@@ -106,6 +113,25 @@ def strategy(self, opponent):
             my_last_move)
         return actions[original_action]
 
+    def _release_shared_library(self):
+        # While this looks like we're checking that the shared library file
+        # isn't deleted, the exception is actually thrown if the manager
+        # thread closes before the player class is garbage collected, which
+        # tends to happen at the end of a script.
+        try:
+            shared_library_manager.release(self.original_name, self.index)
+        except FileNotFoundError:
+            pass
+
     def reset(self):
+        # Release the shared library since the object is rebuilt on reset.
+        self._release_shared_library()
         super().reset()
         self.original_function = self.original_name
+
+    def __del__(self):
+        # Release the library before deletion.
+        self._release_shared_library()
+
+    def __repr__(self):
+        return self.original_name
diff --git a/src/axelrod_fortran/shared_library_manager.py b/src/axelrod_fortran/shared_library_manager.py
new file mode 100644
index 0000000..8fadf6b
--- /dev/null
+++ b/src/axelrod_fortran/shared_library_manager.py
@@ -0,0 +1,120 @@
+from collections import defaultdict
+from ctypes import cdll
+from ctypes.util import find_library
+from multiprocessing.managers import BaseManager
+from pathlib import Path
+import platform
+import shutil
+import subprocess
+import tempfile
+import uuid
+
+
+def load_library(filename):
+    """Loads a shared library."""
+    lib = None
+    if Path(filename).exists():
+        lib = cdll.LoadLibrary(filename)
+    return lib
+
+
+class SharedLibraryManager(object):
+    """LibraryManager creates (and deletes) copies of a shared library, which
+    enables multiple copies of the same strategy to be run without the end user
+    having to maintain many copies of the shared library.
+
+    This works by making a copy of the shared library file and loading it into
+    memory again. Loading the same file again will return a reference to the
+    same memory addresses. To be thread-safe, this class just passes filenames
+    back to the Player class (which actually loads a reference to the library),
+    ensuring that multiple copies of a given player type do not use the same
+    copy of the shared library.
+    """
+
+    def __init__(self, shared_library_name, verbose=False):
+        self.shared_library_name = shared_library_name
+        self.verbose = verbose
+        self.filenames = []
+        self.player_indices = defaultdict(set)
+        self.player_next = defaultdict(set)
+        # Generate a random prefix for tempfile generation
+        self.prefix = str(uuid.uuid4())
+        self.library_path = self.find_shared_library(shared_library_name)
+
+    def find_shared_library(self, shared_library_name):
+        # Hack for Linux since find_library doesn't return the full path.
+        if 'Linux' in platform.system():
+            output = subprocess.check_output(["ldconfig", "-p"])
+            for line in str(output).split(r"\n"):
+                rhs = line.split(" => ")[-1]
+                if shared_library_name in rhs:
+                    return rhs
+            raise ValueError("{} not found".format(shared_library_name))
+        else:
+            return find_library(
+                shared_library_name.replace("lib", "").replace(".so", ""))
+
+    def create_library_copy(self):
+        """Create a new copy of the shared library."""
+        # Copy the library file to a new (temp) location.
+        temp_directory = tempfile.gettempdir()
+        copy_number = len(self.filenames)
+        filename =  "{}-{}-{}".format(
+            self.prefix,
+            str(copy_number),
+            self.shared_library_name)
+        new_filename = str(Path(temp_directory, filename))
+        if self.verbose:
+            print("Loading {}".format(new_filename))
+        shutil.copy2(self.library_path, new_filename)
+        self.filenames.append(new_filename)
+
+    def next_player_index(self, name):
+        """Determine the index of the next free shared library copy to
+        allocate for the player. If none is available then make another copy."""
+        # Is there a free index?
+        if len(self.player_next[name]) > 0:
+            return self.player_next[name].pop()
+        # Do we need to load a new copy?
+        player_count = len(self.player_indices[name])
+        if player_count == len(self.filenames):
+            self.create_library_copy()
+            return player_count
+        # Find the first unused index
+        for i in range(len(self.filenames)):
+            if i not in self.player_indices[name]:
+                return i
+        raise ValueError("We shouldn't be here.")
+
+    def get_filename_for_player(self, name):
+        """For a given player return a filename for a copy of the shared library
+        for use in a Player class, along with an index for later releasing."""
+        index = self.next_player_index(name)
+        self.player_indices[name].add(index)
+        if self.verbose:
+            print("allocating {}".format(index))
+        return index, self.filenames[index]
+
+    def release(self, name, index):
+        """Release the copy of the library so that it can be re-allocated."""
+        self.player_indices[name].remove(index)
+        if self.verbose:
+            print("releasing {}".format(index))
+        self.player_next[name].add(index)
+
+    def __del__(self):
+        """Cleanup temp files on object deletion."""
+        for filename in self.filenames:
+            path = Path(filename)
+            if path.exists():
+                if self.verbose:
+                    print("deleting", str(path))
+                path.unlink()
+
+
+# Setup up thread safe library manager.
+class MultiprocessManager(BaseManager):
+    pass
+
+
+MultiprocessManager.register('SharedLibraryManager', SharedLibraryManager)
diff --git a/tests/test_player.py b/tests/test_player.py
index 9d497d4..8425697 100644
--- a/tests/test_player.py
+++ b/tests/test_player.py
@@ -1,12 +1,14 @@
-from axelrod_fortran import Player, characteristics, all_strategies
-from axelrod import (Alternator, Cooperator, Defector,
-                     Match, Game, basic_strategies, seed)
-from axelrod.action import Action
 from ctypes import c_int, c_float, POINTER, CDLL
-
 import itertools
+
 import pytest
 
+from axelrod_fortran import Player, characteristics, all_strategies
+from axelrod import (Alternator, Cooperator, Defector, Match, MoranProcess,
+                     Game, basic_strategies, seed)
+from axelrod.action import Action
+
+
 C, D = Action.C, Action.D
 
 
@@ -22,15 +24,6 @@ def test_init():
         assert player.original_function.restype == c_int
         with pytest.raises(ValueError):
             player = Player('test')
-        assert "libstrategies.so" == player.shared_library_name
-        assert type(player.shared_library) is CDLL
-        assert "libstrategies.so" in str(player.shared_library)
-
-def test_init_with_shared():
-    player = Player("k42r", shared_library_name="libstrategies.so")
-    assert "libstrategies.so" == player.shared_library_name
-    assert type(player.shared_library) is CDLL
-    assert "libstrategies.so" in str(player.shared_library)
 
 
 def test_matches():
@@ -106,6 +99,7 @@ def test_original_strategy():
                 my_score += scores[0]
                 their_score += scores[1]
 
+
 def test_deterministic_strategies():
     """
     Test that the strategies classified as deterministic indeed act
@@ -139,6 +133,7 @@ def test_implemented_strategies():
                 axl_match = Match((axl_player, opponent))
                 assert interactions == axl_match.play(), (player, opponent)
 
+
 def test_champion_v_alternator():
     """
     Specific regression test for a bug.
@@ -155,18 +150,20 @@ def test_champion_v_alternator():
     seed(0)
     assert interactions == match.play()
 
+
 def test_warning_for_self_interaction(recwarn):
     """
     Test that a warning is given for a self interaction.
     """
     player = Player("k42r")
-    opponent = Player("k42r")
+    opponent = player
 
     match = Match((player, opponent))
 
     interactions = match.play()
     assert len(recwarn) == 1
 
+
 def test_no_warning_for_normal_interaction(recwarn):
     """
     Test that a warning is not given for a normal interaction
@@ -180,3 +177,11 @@ def test_no_warning_for_normal_interaction(recwarn):
 
         interactions = match.play()
         assert len(recwarn) == 0
+
+
+def test_multiple_copies(recwarn):
+    players = [Player('ktitfortatc') for _ in range(5)] + [
+        Player('k42r') for _ in range(5)]
+    mp = MoranProcess(players)
+    mp.play()
+    mp.populations_plot()
diff --git a/tests/test_titfortat.py b/tests/test_titfortat.py
index b70160e..e13b425 100644
--- a/tests/test_titfortat.py
+++ b/tests/test_titfortat.py
@@ -24,3 +24,10 @@ def test_versus_defector():
     match = axl.Match(players, 5)
     expected = [(C, D), (D, D), (D, D), (D, D), (D, D)]
     assert match.play() == expected
+
+
+def test_versus_itself():
+    players = (Player('ktitfortatc'), Player('ktitfortatc'))
+    match = axl.Match(players, 5)
+    expected = [(C, C), (C, C), (C, C), (C, C), (C, C)]
+    assert match.play() == expected