title: Is there a safe method to check if a pthread exists?
body: <p>I'm testing an idea for detailed error handling, and want to enable a thread to have the ability to call a 'getlasterror' function when it needs to work with the error. I'm using a cheap and simple pointer-to-pointers for the structs, but also make use of the <code>pthread_t</code> id to overwrite a previous entry (if the error info was not needed or has been processed).</p>
  
  <p>From the stackoverflow posts <a href="https://stackoverflow.com/questions/2156353/how-do-you-query-a-pthread-to-see-if-it-is-still-running">How do you query a pthread to see if it is still running?</a> and <a href="https://stackoverflow.com/questions/1693180/how-do-i-determine-if-a-pthread-is-alive">How do I determine if a pthread is alive?</a>, it seems using <code>pthread_kill</code> to send a fake signal is potentially unsafe. Is there really no alternative mechanism to check if a pthread with an id exists or not? Or can I disable the ability for thread ids to be reused at runtime? (I'm aware the latter may be a security issue...)</p>
  
  <p>I'd not previously written any code, but I whipped up roughly what my plan would look like below in leafpad (so ignore any syntax errors, if any!). Point of interest is naturally the dynamic cleanup, there's no problem if the application is closing. Any other alternative ideas would also be welcome :)</p>
  
  <p>If applicable, this will be a client/server program, hence a new thread will exist with each <code>accept()</code>.</p>
  
  <pre><code>struct error_info_structs
  {
      struct error_info** errs;   // error_info struct with details
      pthread_t**         tids;   // thread ids for each struct
      uint32_t            num;    // number of error_info structs and thread ids
      pthread_mutex_lock  lock;   // runtime locker
  };
  struct error_info_structs   g_errs;
  // assume we've done necessary initialization...
  
  struct error_info*
  get_last_runtime_error()
  {
      struct error_info*  retval = NULL;
      pthread_t           tid = pthread_self();
  
      pthread_mutex_lock(&amp;g_errs.lock);
  
      for ( uint32_t i = 0; i &lt; g_errs.num; i++ )
      {
          if ( pthread_equal(g_errs.tids[i], tid) )
          {
              retval = g_errs.errs[i];
              goto release_lock;
          }
      }
  
  release_lock:
      pthread_mutex_unlock(&amp;g_errs.lock);
      return retval;
  }
  
  
  void
  raise_runtime_error(struct error_info* ei)
  {
      pthread_t   tid = pthread_self();
  
      pthread_mutex_lock(&amp;g_errs.lock);
  
      for ( uint32_t i = 0; i &lt; g_errs.num; i++ )
      {
          if ( pthread_equal(g_errs.tids[i], tid) )
          {
              // replace existing
              memcpy(&amp;g_errs.errs[i], ei, sizeof(error_info));
              goto release_lock;
          }
  
          /*
           * Dynamic cleanup to lower risk of resource exhaustion.
           * Do it here, where we actually allocate the memory, forcing
           * this to be processed at least whenever a new thread raises
           * an error.
           */
          if ( pthread_kill(g_errs.tids[i], 0) != 0 )
          {
              // doesn't exist, free memory. safe to adjust counter.
              free(g_errs.errs[i]);
              free(g_errs.tids[i]);
              g_errs.num--;
          }
      }
  
      /*
       * first error reported by this thread id. allocate memory to hold its
       * details, eventually free when thread no longer exists.
       */
  
      struct error_info*  newei = malloc(sizeof(struct error_info));
      if ( newei == NULL )
      {
          goto release_lock;
      }
  
      pthread_t*      newt = malloc(sizeof(pthread_t));
      if ( newt == NULL )
      {
          free(newei);
          goto release_lock;
      }
  
      // realloc-bits omitted
  
      g_errs.errs[g_errs.num] = newei;
      g_errs.tids[g_errs.num] = newt;
      g_errs.num++;
  
  release_lock:
      pthread_mutex_unlock(&amp;g_errs.lock);
  }
  </code></pre>