title: pthread_cond_wait deadlock in fifo circular queue
body: <p>my code is only using in one producer-one consumer situation.</p>
  
  <p>here is my test code:</p>
  
  <pre><code>static void *afunc(void * arg) {
      Queue* q  = arg;
      for(int i= 0; i&lt; 100000; i++) {
          *queue_pull(q) = i; //get one element space
          queue_push(q);      //increase the write pointer
      }
      return NULL;
  }
  static void *bfunc(void * arg) {
      Queue* q  = arg;
      for(;;) {
          int *i = queue_fetch(q); //get the first element in queue
          printf("%d\n", *i);
          queue_pop(q);   //increase the read pointer
      }
  }
  int main() {
      Queue queue;
      pthread_t a, b;
      queue_init(&amp;queue);
      pthread_create(&amp;a, NULL, afunc, &amp;queue);
      pthread_create(&amp;b, NULL, bfunc, &amp;queue);
  
      sleep(100000);
      return 0;
  }
  </code></pre>
  
  <p>and here is the implementation of the circular queue</p>
  
  <pre><code>#define MAX_QUEUE_SIZE 3
  typedef struct Queue{ 
      int data[MAX_QUEUE_SIZE] ; 
      int read,write; 
      pthread_mutex_t mutex, mutex2; 
      pthread_cond_t not_empty, not_full; 
  }Queue; 
  int queue_init(Queue *queue) { 
      memset(queue, 0, sizeof(Queue)); 
      pthread_mutex_init(&amp;queue-&gt;mutex, NULL); 
      pthread_cond_init(&amp;queue-&gt;not_empty, NULL); 
      pthread_mutex_init(&amp;queue-&gt;mutex2, NULL); 
      pthread_cond_init(&amp;queue-&gt;not_full, NULL); 
      return 0; 
  } 
  int* queue_fetch(Queue *queue) { 
      int* ret; 
      if (queue-&gt;read == queue-&gt;write) {
          pthread_mutex_lock(&amp;queue-&gt;mutex); 
          pthread_cond_wait(&amp;queue-&gt;not_empty, &amp;queue-&gt;mutex); 
          pthread_mutex_unlock(&amp;queue-&gt;mutex); 
      } 
      ret = &amp;(queue-&gt;data[queue-&gt;read]); 
      return ret; 
  } 
  void queue_pop(Queue *queue) { 
      nx_atomic_set(queue-&gt;read, (queue-&gt;read+1)%MAX_QUEUE_SIZE); 
      pthread_cond_signal(&amp;queue-&gt;not_full); 
  } 
  int*  queue_pull(Queue *queue) { 
      int* ret; 
      if ((queue-&gt;write+1)%MAX_QUEUE_SIZE == queue-&gt;read) { 
          pthread_mutex_lock(&amp;queue-&gt;mutex2); 
          pthread_cond_wait(&amp;queue-&gt;not_full, &amp;queue-&gt;mutex2); 
          pthread_mutex_unlock(&amp;queue-&gt;mutex2); 
      } 
      ret = &amp;(queue-&gt;data[queue-&gt;write]); 
      return ret; 
  } 
  void queue_push(Queue *queue) { 
          nx_atomic_set(queue-&gt;write, (queue-&gt;write+1)%MAX_QUEUE_SIZE); 
          pthread_cond_signal(&amp;queue-&gt;not_empty); 
  } 
  </code></pre>
  
  <p>after a few moments, it seems the two child threads will turn into deadlock..</p>
  
  <p>EDIT: i use two semaphore， but it also has some problem.. it's pretty
  weird, if if just execute ./main, it seems fine, but if i redirect into a file, like ./main > a.txt,  then wc -l a.txt, the result is not equal the enqueue number..</p>
  
  <pre><code>int queue_init(Queue *queue) {
      memset(queue, 0, sizeof(Queue));
      pthread_mutex_init(&amp;queue-&gt;mutex, NULL);
      sem_unlink("/not_empty");
      queue-&gt;not_empty = sem_open("/not_empty", O_CREAT, 644, 0);
      sem_unlink("/not_full");
      queue-&gt;not_full = sem_open("/not_full", O_CREAT, 644, MAX_QUEUE_SIZE);
      return 0;
  }
  
  int* queue_fetch(Queue *queue) {
      sem_wait(queue-&gt;not_empty);
      return &amp;(queue-&gt;data[queue-&gt;read]);
  }
  void queue_pop(Queue *queue) {
      nx_atomic_set(queue-&gt;read, (queue-&gt;read+1)%MAX_QUEUE_SIZE);
      sem_post(queue-&gt;not_full);
  }
  
  int* queue_pull(Queue *queue) {
      sem_wait(queue-&gt;not_full);
      return  &amp;(queue-&gt;data[queue-&gt;write]);
  }
  void queue_push(Queue *queue) {
      nx_atomic_set(queue-&gt;write, (queue-&gt;write+1)%MAX_QUEUE_SIZE);
      sem_post(queue-&gt;not_empty);
  }
  </code></pre>