What is blocking and the re-entrant concept in general?

I am always embarrassed. Can anyone explain what Reentrant means in different contexts? And why do you want to use reentrant or irrevocable?

Say pthread (posix) fixing primitives, are they repetitive or not? What disadvantages should be avoided when using them?

Is re-entry mutex?

+74
multithreading pthreads locking
Aug 21 '09 at 14:22
source share
4 answers

Re-Login Lock

The reentrant lock is such that the process may require the lock several times without blocking by itself. This is useful in situations where it is not easy to keep track of whether you have captured the castle. If the lock is not a retry, you can lock it and then lock it when you go to lock it again, effectively blocking your process.

Reentrancy as a whole is a property of the code in which it does not have a central mutable state that could be damaged if the code was called during its execution. Such a call can be made by another thread, or it can be recursively implemented by execution, proceeding from the code itself.

If the code depends on the general state, which can be updated in the middle of its execution, it is not repeated, at least if this update can break it.

Use case for blocking re-entry

A (somewhat general and far-fetched) example application for blocking re-entry may be:

  • You have some calculations using an algorithm that intersects the graph (possibly with loops in it). A crawl may visit the same node more than once due to loops or due to multiple paths to the same node.

  • The data structure is subject to concurrent access and may be updated for some reason, possibly another thread. You should be able to block individual nodes to deal with potential data corruption due to race conditions. For some reason (possibly performance) you don’t want to globally lock the entire data structure.

  • You cannot save full information about which sites you visited, or use a data structure that does not allow me to "be here before" to respond quickly.
    >
    An example of such a situation would be a simple implementation of the Dijkstra algorithm with a priority queue implemented as a binary heap or a width search using a simple linked list as a queue. In these cases, the queue check for existing inserts is O (N), and you cannot do this at each iteration.

In this situation, tracking which locks you have already purchased is expensive. Assuming you want to lock at the node level, the re-entry lock mechanism makes it easier to figure out if you visited the node before. You can just blindly block a node, perhaps unlock it after you pull it out of the queue.

Reentry Metutes

A simple mutex is not repeated, since only one thread can be in a critical section at a given time. If you take a mutex and then try to capture it again, a simple mutex will not have enough information to tell who held it before. To do this recursively, you need a mechanism in which each thread has a token so that you can find out who captured the mutex. This makes the mutex mechanism somewhat more expensive, so you cannot do this in all situations.

The POSIX IIRC Thread API offers the ability to re-enter and intercept mutexes.

+135
Aug 21 '09 at 14:25
source share

The reentry lock allows you to write a method M that places the lock on resource A and then calls M recursively or from code that already contains the lock on A

With locking without re-entry, you will need two versions of M , one of which is blocked, and the other is not, and the additional logic is correct.

+19
Aug 21 '09 at 14:33
source share

Reentor locking is very well described in this tutorial .

The example in the textbook is much less contrived than in the answer about going around the chart. Retentate blocking is useful in very simple cases.

+11
Mar 05 '14 at 12:35
source share

What and why a recursive mutex should not be such a complicated thing as described in the accepted answer.

I would like to write down my understanding after some digging on the net.




First, you must understand that when it comes to a mutex, multi-threaded concepts are also clearly involved. (mutex is used for synchronization. I do not need a mutex if there is only 1 thread in my program)




Secondly, you need to know the difference between a normal mutex and a recursive mutex .

Quoted from APUE:

(A recursive mutex is) A mutex type that allows the same thread to block it several times, without first unlocking it.

The main difference is that a recursive lock inside the same thread does not cause deadlock and does not block the thread.

Does this mean that recursive locking never causes a deadlock?
No, it can still cause a deadlock like a regular mutex if you blocked it in one thread without unlocking it and tried to block it in other threads.

Let's see the code as evidence.

  1. normal mutex with a dead end
 #include <pthread.h> #include <stdio.h> pthread_mutex_t lock; void * func1(void *arg){ printf("thread1\n"); pthread_mutex_lock(&lock); printf("thread1 hey hey\n"); } void * func2(void *arg){ printf("thread2\n"); pthread_mutex_lock(&lock); printf("thread2 hey hey\n"); } int main(){ pthread_mutexattr_t lock_attr; int error; // error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE); error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT); if(error){ perror(NULL); } pthread_mutex_init(&lock, &lock_attr); pthread_t t1, t2; pthread_create(&t1, NULL, func1, NULL); pthread_create(&t2, NULL, func2, NULL); pthread_join(t2, NULL); } 

exit:

 thread1 thread1 hey hey thread2 

An example of a common dead end, no problem.

  1. recursive mutex with dead end

Just uncomment this line
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
and comment on another.

exit:

 thread1 thread1 hey hey thread2 

Yes, a recursive mutex can also cause a dead end.

  1. normal mutex, lock in the same topic
 #include <pthread.h> #include <stdio.h> #include <unistd.h> pthread_mutex_t lock; void func3(){ printf("func3\n"); pthread_mutex_lock(&lock); printf("func3 hey hey\n"); } void * func1(void *arg){ printf("thread1\n"); pthread_mutex_lock(&lock); func3(); printf("thread1 hey hey\n"); } void * func2(void *arg){ printf("thread2\n"); pthread_mutex_lock(&lock); printf("thread2 hey hey\n"); } int main(){ pthread_mutexattr_t lock_attr; int error; // error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE); error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT); if(error){ perror(NULL); } pthread_mutex_init(&lock, &lock_attr); pthread_t t1, t2; pthread_create(&t1, NULL, func1, NULL); sleep(2); pthread_create(&t2, NULL, func2, NULL); pthread_join(t2, NULL); } 

exit:

 thread1 func3 thread2 

Deadlock in thread t1 , in func3 .
(I use sleep(2) to make it easier to see that the deadlock is primarily caused by locking in func3 )

  1. recursive mutex, blocking in the same thread

Again, uncomment the line of the recursive mutex and comment out the other line.

exit:

 thread1 func3 func3 hey hey thread1 hey hey thread2 

Deadlock in thread t2 , in func2 . See? func3 shuts down and exits; re-locking does not block the thread and does not cause deadlock.




So the last question, why do we need this?

For a recursive function (called in multi-threaded programs and you want to protect some resources / data).

For example, you have a multi-threaded program, and you call a recursive function in thread A. You have some data that you want to protect in this recursive function, so you use the mutex mechanism. The execution of this function is sequential in thread A, so you will definitely lock the mutex in recursion. Using a normal mutex causes deadlocks. And an inventive mutex is invented to solve this.

See an example from the accepted answer. When to use a recursive mutex? ,

Wikipedia explains the recursive mutex very well. Definitely worth reading. Wikipedia: Reentrant_mutex

0
Apr 15 '19 at 9:41
source share



All Articles