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);
}
}
Secondly, the std::mutex is implemented in way that it spin locks for a bit before actually doing system calls when it fails to immediately obtain the lock on a mutex (which no doubt will be extremely slow).
Mutexes are used to protect shared resources. If the mutex is already locked by another thread, the thread waits for the mutex to become available. The thread that has locked a mutex becomes its current owner and remains the owner until the same thread has unlocked it.
pthread_mutex_lock() doesn't cause only the calling thread to execute. Rather, it does one of two things: If the mutex wasn't already locked, it locks the mutex and returns immediately. If the mutex was already locked, it puts the calling thread to sleep, to wait until the mutex has become unlocked.
Instead of worrying about the blades of grass, step back and observe the whole forest.
Any algorithm which depends on two threads potentially closely stepping on each each other's toes is inherently inefficient. Try to find a way to drastically reduce the need for interaction.
For example, if one thread produces data and the other consumes it, one can easily think up an inefficient algorithm where the producer publishes the data in shared memory and then waits for the other to consume it. Meanwhile the consumer is waiting for the producer to finish, etc., etc. This is all much simplified by the producer writing into a file or pipe, and the consumer reading from it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With