problem with pthread_cancel
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

problem with pthread_cancel



-------- Problem description ----------

Using the pthread library, I tried to implement a multi-threading application.
At each time, at most one thread should be running. Therefore, when I create a new
thread, it immediately waits using pthread_cond_wait. And it's signalled when it should
proceed (using pam_resume and pam_suspend).

It seems to work perfectly, until I make use of pam_destroy, to destory a thread that
is not running.
The problem is, when the pthread_cancel is called, this thread is in a pthread_cond_wait.
That is a cancellation point, and the thread does exit. However, AFTER this new threads
do not run anymore. I create a new one, and it will get blocked in pthread_cond_wait.

Can anybody spot the mistake? Something wrong with a mutex_lock / unlock ?
Should macro pam_destory do more than only a call to pthread_cancel ?

Thanks in advance,
JeeBee.

-------- fragment of pam.m ------------

// destroy thread pro
// IN: pam_proc *pro
#define pam_destroy(pro) do { \
  if(pthread_cancel((pro)->tid->thread)) { \
	pam_fatal("pam_destroy: could not cancel thread"); \
  } \
} while(0)

// resume current thread
#define pam_resume() do { \
  /*printf("Signalling thread %d to continue.\n", pam_root->tid->thread);*/ \
  pthread_mutex_lock(&condition_mutex); \
  pthread_cond_signal(&pam_root->tid->condition_cond); \
} while(0)

// suspend old thread
// IN: pam_proc *old
#define pam_suspend(old) do { \
  pthread_cond_wait(&old->tid->condition_cond, &condition_mutex); \
  pthread_mutex_unlock(&condition_mutex); \
} while(0)

// context switch from old to pam_root
// IN: pam_proc *old
#define pam_context(old) do { \
  if(pam_root->tid != NULL) { \
	pam_resume(); \
	pam_suspend(old); \
  } else { /* NULL proc, resume peer */ \
	pam_peer(old); \
  } \
} while(0)

// transfer control to pam_root and destroy old
// IN: pam_proc old
#define pam_resume_destroy(old) do { \
  pam_resume(); \
  pthread_mutex_unlock(&condition_mutex); \
  pthread_exit(NULL); \
} while(0)
  
#endif

----------- pthreads.c -----------------------

#include "pthreads.h"

#define STACKSIZE (1024*1024) /* 1Mb per thread */

//int pthread_counter = 0;
//struct sched_param pthread_sched_param;
pthread_attr_t pthread_attr;
pthread_mutex_t condition_mutex;
pthread_cond_t thread_create_cond;

int pam_pthread_setup() {
  int rc = 0;
  size_t stacksize;
  
  pthread_mutex_init(&condition_mutex, NULL);
  pthread_cond_init(&thread_create_cond, NULL);
  
  pthread_attr_init(&pthread_attr);
  if((rc = pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED))) {
	fprintf(stderr, "pthread_attr_setdetachstate() returns non-zero (%d).", rc);
	return rc;
  }
 
  /* Check stack size */
  if((rc = pthread_attr_getstacksize(&pthread_attr, &stacksize))) {
	fprintf(stderr, "pthread_attr_getstacksize() returns non-zero (%d).", rc);
	return rc;
  }
  if(stacksize < STACKSIZE) {
	if((rc = pthread_attr_setstacksize(&pthread_attr, STACKSIZE))) {
	  fprintf(stderr, "pthread_attr_setstacksize() returns non-zero (%d).", rc);
	  return rc;
	}
  }
  return 0;
}

void* pam_pthread_func_wrapper(void *arg) {
  pam_tid *me = (pam_tid *) arg;
  
  //printf("Entering the func wrapper for new thread %d.\n", (int)me->thread);

  // pam_suspend
  pthread_mutex_lock(&condition_mutex);
  pthread_cond_signal(&thread_create_cond);
  //printf("Now %d is waiting to be signalled.\n", (int)me->thread);
  pthread_cond_wait(&me->condition_cond, &condition_mutex);
  pthread_mutex_unlock(&condition_mutex);
  
  //printf("Call to func pointer by thread %d.\n", (int)me->thread);
  me->func();
  pthread_exit(0);
  return NULL;
}

// Create a suspended thread
int pam_pthread_create(pam_tid *tid) {
  int rc = 0;
  if((rc = pthread_create(&tid->thread,
		  &pthread_attr, pam_pthread_func_wrapper,
		  (void *)tid) != 0)) {
	fprintf(stderr, "pthread_create() returns non-zero (%d).\n", rc);
  }
  return 0;
}