title: Deallocating memory in multi-threaded environment
body: <p>I'm having a hard time figuring out how to manage deallocation of memory in multithreaded environments. Specifically what I'm having a hard time with is using a lock to protect a structure, but when it's time to free the structure, you have to unlock the lock to destroy the lock itself. Which will cause problems if a separate thread is waiting on that same lock that you need to destroy.</p>
  
  <p>I'm trying to come up with a mechanism that has retain counts, and when the object's retain count is 0, it's all freed. I've been trying a number of different things but just can't get it right. As I've been doing this it seems like you can't put the locking mechanism inside of the structure that you need to be able to free and destroy, because that requires you unlock the the lock inside of it, which could allow another thread to proceed if it was blocked in a lock request for that same structure. Which would mean that something undefined is guaranteed to happen - the lock was destroyed, and deallocated so either you get memory access errors, or you lock on undefined behavior..</p>
  
  <p>Would someone mind looking at my code? I was able to put together a sandboxed example that demonstrates what I'm trying without a bunch of files.</p>
  
  <p><a href="http://pastebin.com/SJC86GDp" rel="nofollow">http://pastebin.com/SJC86GDp</a></p>
  
  <pre><code>#include &lt;pthread.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
  
  struct xatom {
      short rc;
      pthread_rwlock_t * rwlck;
  };
  typedef struct xatom xatom;
  
  struct container {
      xatom * atom;
  };
  typedef struct container container;
  
  #define nr 1
  #define nw 2
  pthread_t readers[nr];
  pthread_t writers[nw];
  
  container * c;
  
  void  retain(container * cont);
  void  release(container ** cont);
  short retain_count(container * cont);
  
  void * rth(void * arg) {
      short rc;
      while(1) {
          if(c == NULL) break;
          rc = retain_count(c);
      }
      printf("rth exit!\n");
      return NULL;
  }
  
  void * wth(void * arg) {
      while(1) {
          if(c == NULL) break;
          release((container **)&amp;c);
      }
      printf("wth exit!\n");
      return NULL;
  }
  
  short retain_count(container * cont) {
      short rc = 1;
      pthread_rwlock_rdlock(cont-&gt;atom-&gt;rwlck);
      printf("got rdlock in retain_count\n");
      rc = cont-&gt;atom-&gt;rc;
      pthread_rwlock_unlock(cont-&gt;atom-&gt;rwlck);
      return rc;
  }
  
  void retain(container * cont) {
      pthread_rwlock_wrlock(cont-&gt;atom-&gt;rwlck);
      printf("got retain write lock\n");
      cont-&gt;atom-&gt;rc++;
      pthread_rwlock_unlock(cont-&gt;atom-&gt;rwlck);
  }
  
  void release(container ** cont) {
      if(!cont || !(*cont)) return;
      container * tmp = *cont;
      pthread_rwlock_t ** lock = (pthread_rwlock_t **)&amp;(*cont)-&gt;atom-&gt;rwlck;
      pthread_rwlock_wrlock(*lock);
      printf("got release write lock\n");
      if(!tmp) {
          printf("return 2\n");
          pthread_rwlock_unlock(*lock);
          if(*lock) {
              printf("destroying lock 1\n");
              pthread_rwlock_destroy(*lock);
              *lock = NULL;
          }
          return;
      }
      tmp-&gt;atom-&gt;rc--;
      if(tmp-&gt;atom-&gt;rc == 0) {
          printf("deallocating!\n");
          *cont = NULL;
          pthread_rwlock_unlock(*lock);
          if(pthread_rwlock_trywrlock(*lock) == 0) {
              printf("destroying lock 2\n");
              pthread_rwlock_destroy(*lock);
              *lock = NULL;
          }
          free(tmp-&gt;atom-&gt;rwlck);
          free(tmp-&gt;atom);
          free(tmp);
      } else {
          pthread_rwlock_unlock(*lock);
      }
  }
  
  container * new_container() {
      container * cont = malloc(sizeof(container));
      cont-&gt;atom = malloc(sizeof(xatom));
      cont-&gt;atom-&gt;rwlck = malloc(sizeof(pthread_rwlock_t));
      pthread_rwlock_init(cont-&gt;atom-&gt;rwlck,NULL);
      cont-&gt;atom-&gt;rc = 1;
      return cont;
  }
  
  int main(int argc, char ** argv) {
      c = new_container();
      int i = 0;
      int l = 4;
      for(i=0;i&lt;l;i++) retain(c);
      for(i=0;i&lt;nr;i++) pthread_create(&amp;readers[i],NULL,&amp;rth,NULL);
      for(i=0;i&lt;nw;i++) pthread_create(&amp;writers[i],NULL,&amp;wth,NULL);
      sleep(2);
      for(i=0;i&lt;nr;i++) pthread_join(readers[i],NULL);
      for(i=0;i&lt;nw;i++) pthread_join(writers[i],NULL);
      return 0;
  }
  </code></pre>
  
  <p>Thanks for any help!</p>