Index: server/lib/gutenbach/server/__init__.py
===================================================================
--- server/lib/gutenbach/server/__init__.py	(revision a9eb577e4cd2b47f81db5ec3c68805dcb0e6362b)
+++ server/lib/gutenbach/server/__init__.py	(revision cf0d7e841609343938618ddcce617a7fdb26fd9a)
@@ -3,4 +3,18 @@
 __all__ = ['errors']
 __all__.extend(errors.__all__)
+
+def sync(func):
+    """Lock decorator
+
+    Holds a lock (self.lock) for the durration of a method call.
+    """
+
+    def do(self, *args, **kwargs):
+        with self.lock:
+            return func(self, *args, **kwargs)
+
+    return do
+__all__.append('sync')
+
 
 from job import GutenbachJob
Index: server/lib/gutenbach/server/player.py
===================================================================
--- server/lib/gutenbach/server/player.py	(revision a9eb577e4cd2b47f81db5ec3c68805dcb0e6362b)
+++ server/lib/gutenbach/server/player.py	(revision cf0d7e841609343938618ddcce617a7fdb26fd9a)
@@ -3,4 +3,5 @@
 import subprocess
 import time
+from . import sync
 
 # initialize logger
@@ -24,20 +25,18 @@
 
     @property
+    @sync
     def is_playing(self):
-        with self.lock:
-            if self._dryrun:
-                playing = self.isAlive() and not self.is_done
-            else:
-                playing = self.isAlive() and \
-                          not self.is_done and \
-                          self.player is not None and \
-                          self.player.poll() is None
-        return playing
+        if self._dryrun:
+            return self.isAlive() and not self.is_done
+        else:
+            return self.isAlive() and \
+                      not self.is_done and \
+                      self.player is not None and \
+                      self.player.poll() is None
 
     @property
+    @sync
     def is_paused(self):
-        with self.lock:
-            paused = self.is_playing and self._paused
-        return paused
+        return self.is_playing and self._paused
 
     @property
@@ -49,7 +48,7 @@
         return self._callback
     @callback.setter
+    @sync
     def callback(self, val):
-        with self.lock:
-            self._callback = val
+        self._callback = val
 
     def start(self):
@@ -112,4 +111,5 @@
 
     def mplayer_pause(self):
+        # Note: Inner lock due to sleep.
         with self.lock:
             if self.is_playing:
@@ -123,4 +123,5 @@
                 
     def mplayer_stop(self):
+        # Note: Inner Lock due to join.
         with self.lock:
             if self.is_playing:
Index: server/lib/gutenbach/server/printer.py
===================================================================
--- server/lib/gutenbach/server/printer.py	(revision 609a9b0caa8f39f0ce4bf43ec240d742f11ed07f)
+++ server/lib/gutenbach/server/printer.py	(revision cf0d7e841609343938618ddcce617a7fdb26fd9a)
@@ -9,4 +9,5 @@
 import traceback
 import sys
+from . import sync
 
 
@@ -124,20 +125,19 @@
 
     @property
+    @sync
     def state(self):
-        with self.lock:
-            if self.current_job is not None:
-                val = States.PROCESSING
-            elif len(self.pending_jobs) == 0:
-                val = States.IDLE
-            else:
-                val = States.STOPPED
-        return val
-
-    @property
+        if self.current_job is not None:
+            return States.PROCESSING
+        elif len(self.pending_jobs) == 0:
+            return States.IDLE
+        else:
+            return States.STOPPED
+
+    @property
+    @sync
     def active_jobs(self):
-        with self.lock:
-            jobs = self.pending_jobs[:]
-            if self.current_job is not None:
-                jobs.insert(0, self.current_job.id)
+        jobs = self.pending_jobs[:]
+        if self.current_job is not None:
+            jobs.insert(0, self.current_job.id)
         return jobs
 
@@ -146,35 +146,34 @@
     ######################################################################
 
+    @sync
     def start_job(self):
-        with self.lock:
-            if self.current_job is None:
-                try:
-                    job_id = heapq.heappop(self.pending_jobs)
-                    self.current_job = self.get_job(job_id)
-                    self.current_job.play()
-                except IndexError:
-                    self.current_job = None
-                except InvalidJobStateException:
-                    heapq.heappush(self.pending_jobs, self.current_job.id)
-                    self.current_job = None
+        if self.current_job is None:
+            try:
+                job_id = heapq.heappop(self.pending_jobs)
+                self.current_job = self.get_job(job_id)
+                self.current_job.play()
+            except IndexError:
+                self.current_job = None
+            except InvalidJobStateException:
+                heapq.heappush(self.pending_jobs, self.current_job.id)
+                self.current_job = None
                     
+    @sync
     def complete_job(self):
-        with self.lock:
-            if self.current_job is None:
-                return
-
-            try:
-                if not self.current_job.is_done:
-                    self.current_job.stop()
-            finally:
-                self.finished_jobs.append(self.current_job.id)
-                self.current_job = None
-
+        if self.current_job is None:
+            return
+
+        try:
+            if not self.current_job.is_done:
+                self.current_job.stop()
+        finally:
+            self.finished_jobs.append(self.current_job.id)
+            self.current_job = None
+
+    @sync
     def get_job(self, job_id):
-        with self.lock:
-            if job_id not in self.jobs:
-                raise InvalidJobException(job_id)
-            job = self.jobs[job_id]
-        return job
+        if job_id not in self.jobs:
+            raise InvalidJobException(job_id)
+        return self.jobs[job_id]
 
     ######################################################################
