Alex Rivera | Logout

Performance of pthread_mutex_lock/unlock

Asked 2011-06-23T20:59:41.430
12

I've noticed that I take a pretty big performance hit when I have an algorithm that locks and unlocks a thread ALOT.

Is there any way to help this overhead? Would using a semaphore be more/less efficient?

Thanks

typedef struct _treenode{
   struct _treenode *leftNode;
   struct _treenode *rightNode;
   int32_t data;
   pthread_mutex_t mutex;
}TreeNode;

pthread_mutex_t _initMutex = PTHREAD_MUTEX_INITIALIZER;

int32_t insertNode(TreeNode **_trunk, int32_t data){
   TreeNode **current;
   pthread_mutex_t *parentMutex = NULL, *currentMutex = &_initMutex;

   if(_trunk != NULL){
      current = _trunk;
      while(*current != NULL){
         pthread_mutex_lock(&(*current)->mutex);
         currentMutex = &(*current)->mutex;
         if((*current)->data < data){
            if(parentMutex != NULL)
               pthread_mutex_unlock(parentMutex);
            pthreadMutex = currentMutex;
            current = &(*current)->rightNode;
         }else if((*current)->data > data){
            if(parentMutex != NULL)
               pthread_mutex_unlock(parentMutex);
            parentMutex = currentMutex;
            current = &(*current)->leftNode;
         }else{
            pthread_mutex_unlock(currentMutex);
            if(parentMutex != NULL)
               pthread_mutex_unlock(parentMutex);
            return 0;
         }
      }
      *current = malloc(sizeof(TreeNode));
      pthread_mutex_init(&(*current)->mutex, NULL);
      pthread_mutex_lock(&(*current)->mutex);
      (*current)->leftNode = NULL;
      (*current)->rightNode = NULL;
      (*current)->data = data;
      pthread_mutex_unlock(&(*current)->mutex);
      pthread_mutex_unlock(currentMutex);
   }else{
      return 1;
   }
   return 0;
}

int main(){
   int i;
   TreeNode *trunk = NULL;
   for(i=0; i<1000000; i++){
      insertNode(&trunk, rand() % 50000);
   }
}
Edit
Report

1 Answer

15

pthread_mutex_lock and pthread_mutex_unlock vary in cost depending on contention:

  1. Single thread use - either only one thread exists, or only one thread is using the mutex and the resource it protects: locking is virtually free, perhaps 80-100 cycles at most.
  2. Multiple threads using the resource, but locks are held for very short intervals and contention is rare: locking has some cost, and it's hard to measure; the cost consists mostly of invalidating other cores'/cpus' cache lines.
  3. Significant lock contention: nearly every lock and unlock operation will require assistance from the kernel, and the cost is easily several thousand (possibly even tens of thousand) cycles per lock/unlock.

Still, mutexes should be the least expensive locking primitive in most situations and on most implementations. Occasionally spinlocks may perform better. I would never expect semaphores to perform better.

answered 2011-06-23T21:26:51.313

Your Answer