Existe-t-il une différence entre un sémaphore binaire et un mutex ou sont-ils essentiellement les mêmes?
Ils sont PAS la même chose. Ils sont utilisés à des fins différentes!
Alors que les deux types de sémaphores ont un état plein/vide et utilisent la même API, leur utilisation est très différente.
Sémaphores d'Exclusion Mutuelle
Les sémaphores d’exclusion mutuelle servent à protéger les ressources partagées (structure de données, fichier, etc.).
Un sémaphore Mutex "appartient" à la tâche qui le prend. Si la tâche B tente de semGriver un mutex actuellement détenu par la tâche A, l'appel de la tâche B renverra une erreur et échouera.
Les mutex utilisent toujours la séquence suivante:
- SemTake - Section critique - SemGive
Voici un exemple simple:
Fil A Fil B Prendre un mutex Accéder aux données ... Prendre un mutex <== Bloquera ... Donner aux données d'accès au mutex <== Débloquer ... Donner à Mutex
Sémaphore binaire
Binary Semaphore aborde une question totalement différente:
Task A Task B
... Take BinSemaphore <== wait for something
Do Something Noteworthy
Give BinSemaphore do something <== unblocks
Notez qu'avec un sémaphore binaire, il est normal que B prenne le sémaphore et A pour le lui donner.
Encore une fois, un sémaphore binaire ne protège PAS une ressource de tout accès. L'acte de donner et de prendre un sémaphore est fondamentalement découplé.
Cela n’a généralement pas de sens de donner la même tâche à un même sémaphore binaire.
L’exemple des toilettes est une analogie agréable:
Mutex:
Est-ce une clé pour une toilette. Une personne peut avoir la clé - occuper les toilettes - à la fois. Une fois l'opération terminée, la personne donne (libère) la clé à la prochaine personne dans la file d'attente.
Officiellement: "Les mutex sont généralement utilisés pour sérialiser l’accès à une section de code réentrant qui ne peut pas être exécutée simultanément par plusieurs threads. Un objet mutex ne permet qu’un thread dans une section contrôlée, forçant les autres threads tentant d'accéder à cette section à attendre jusqu'à ce que le premier thread est sorti de cette section ". Ref: Bibliothèque de développement Symbian
(Un mutex est vraiment un sémaphore de valeur 1.)
Sémaphore:
Est-ce le nombre de clés de toilette identiques gratuites? Exemple, disons que nous avons quatre toilettes avec des serrures et des clés identiques. Le nombre de sémaphores - le nombre de clés - est réglé sur 4 au début (les quatre toilettes sont gratuites), puis la valeur du compte est décrémentée au fur et à mesure que les personnes entrent. Si toutes les toilettes sont pleines, c'est-à-dire. il n'y a plus de clés libres, le nombre de sémaphores est 0. Maintenant, quand éq. une personne quitte les toilettes, le sémaphore est augmenté à 1 (une touche libre) et donné à la personne suivante dans la file d'attente.
Officiellement: "Un sémaphore limite le nombre d'utilisateurs simultanés d'une ressource partagée à un nombre maximal. Les threads peuvent demander l'accès à la ressource (décrémentation du sémaphore) et peuvent signaler qu'ils ont fini d'utiliser la ressource (incrémentation du sémaphore). " Ref: Bibliothèque de développement Symbian
Mutex ne peut être libéré que par le thread qui l'a acquis, alors que vous pouvez signaler un sémaphore à partir de tout autre thread (ou processus), les sémaphores sont donc mieux adaptés à certains problèmes de synchronisation tels que producteur-consommateur.
Sous Windows, les sémaphores binaires ressemblent davantage à des objets d’événement qu’à des mutex.
De bons articles sur le sujet:
De la partie 2:
Le mutex est similaire aux principes du sémaphore binaire avec une différence significative: le principe de propriété. La propriété est le concept simple selon lequel, lorsqu'une tâche verrouille (acquiert) un mutex, seule elle peut le déverrouiller. Si une tâche tente de déverrouiller un mutex qu’elle n’a pas verrouillé (donc ne possède pas), une condition d’erreur est rencontrée et, plus important encore, le mutex n’est pas déverrouillé. Si l'objet d'exclusion mutuelle n'a pas de propriété, alors, indépendamment de son nom, ce n'est pas un mutex.
Comme aucune des réponses ci-dessus n’élimine la confusion, en voici une qui a permis de dissiper ma confusion.
À proprement parler, un mutex est un mécanisme de verrouillage utilisé pour synchroniser l'accès à une ressource. Une seule tâche (pouvant être un thread ou un processus basé sur une abstraction du système d'exploitation) peut acquérir le mutex. Cela signifie qu'il y aura une propriété associée à mutex, et que seul le propriétaire peut libérer le verrou (mutex).
Le sémaphore est un mécanisme de signalisation (type de signal "J'ai terminé, vous pouvez continuer"). Par exemple, si vous écoutez des chansons (supposez-le comme une tâche) sur votre mobile et que votre ami vous appelle en même temps, une interruption sera déclenchée, sur laquelle une routine de service d'interruption (ISR) signalera à la tâche de traitement de l'appel de se réveiller. .
Leur sémantique de synchronisation est très différente:
En tant que tel, on peut voir un mutex comme un jeton transmis de tâche en tâche et un sémaphore comme un feu rouge (it signale quelqu'un qu'il peut continuer).
Un Mutex, par définition, est utilisé pour sérialiser l'accès à une section de code réentrant qui ne peut pas être exécutée simultanément par plusieurs threads.
A Semaphore, par définition, limite le nombre d'utilisateurs simultanés d'une ressource partagée à un nombre maximal
Un sémaphore peut être un mutex, mais un mutex ne peut jamais être un sémaphore. Cela signifie simplement qu'un sémaphore binaire peut être utilisé en tant que Mutex, mais qu'un Mutex ne peut jamais présenter les fonctionnalités de sémaphore.
Dans le cas de Mutex, le thread propriétaire du Mutex est responsable de sa libération. Cependant, dans le cas de sémaphores, cette condition n'est pas requise. Tout autre thread peut signaler la libération du sémaphore en utilisant la fonction s m p s (function.e_ot).
Une autre différence importante pour les développeurs est que les sémaphores s’appliquent à l’ensemble du système et restent sous la forme de fichiers sur le système de fichiers, à moins d’être nettoyés. Les mutex sont répartis dans tout le processus et sont nettoyés automatiquement à la fin du processus.
Au niveau théorique, ils ne sont pas différents sémantiquement. Vous pouvez implémenter un mutex en utilisant des sémaphores ou inversement (voir here pour un exemple). En pratique, la mise en œuvre est différente et ils offrent des services légèrement différents.
La différence pratique (en termes de services système les entourant) est que la mise en œuvre d'un mutex vise à être un mécanisme de synchronisation plus léger. En langage Oracle, les mutex sont appelés verrous et les sémaphores sont appelés attend .
Au niveau le plus bas, ils utilisent une sorte de mécanisme test et définition atomique. Ceci lit la valeur actuelle d'un emplacement mémoire, calcule une sorte de conditionnel et écrit une valeur à cet emplacement dans une seule instruction qui ne peut pas être interromp . Cela signifie que vous pouvez acquérir un mutex et tester pour voir si quelqu'un d'autre le possédait avant vous.
Une implémentation de mutex typique comporte un processus ou un thread exécutant l'instruction test-and-set et évaluant si autre chose a défini le mutex. Un point clé ici est qu’il n’ya aucune interaction avec le ordonnanceur , nous n’avons donc aucune idée (et ne nous en soucions pas) de qui a verrouillé le verrou. Ensuite, nous abandonnons notre tranche de temps et essayons à nouveau lorsque la tâche est reprogrammée ou exécutons un verrouillage verrouillé . Un verrou tournant est un algorithme tel que:
Count down from 5000:
i. Execute the test-and-set instruction
ii. If the mutex is clear, we have acquired it in the previous instruction
so we can exit the loop
iii. When we get to zero, give up our time slice.
Lorsque nous avons fini d'exécuter notre code protégé (connu sous le nom de section critique ), nous venons de définir la valeur du mutex sur zéro ou peu importe le sens du mot "effacer". Si plusieurs tâches tentent d'acquérir le mutex, la prochaine tâche planifiée après la publication du mutex aura accès à la ressource. En règle générale, vous utiliseriez des mutex pour contrôler une ressource synchronisée où l'accès exclusif n'est requis que pour de très courtes périodes, normalement pour mettre à jour une structure de données partagée.
Un sémaphore est une structure de données synchronisée (généralement à l'aide d'un mutex) dotée d'un nombre et de certains wrappers d'appels système qui interagissent avec le planificateur de manière un peu plus profonde que ne le feraient les bibliothèques de mutex. Les sémaphores sont incrémentés et décrémentés et utilisés pour bloquer tâches jusqu'à ce que quelque chose d'autre soit prêt. Voir Problème producteur/consommateur pour un exemple simple. Les sémaphores sont initialisés à une certaine valeur - un sémaphore binaire est simplement un cas spécial dans lequel le sémaphore est initialisé à 1. L'enregistrement dans un sémaphore a pour effet de réveiller un processus en attente.
Un algorithme de base de sémaphore ressemble à ceci:
(somewhere in the program startup)
Initialise the semaphore to its start-up value.
Acquiring a semaphore
i. (synchronised) Attempt to decrement the semaphore value
ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.
Posting a semaphore
i. (synchronised) Increment the semaphore value
ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.
iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.
Dans le cas d'un sémaphore binaire, la principale différence pratique entre les deux réside dans la nature des services système entourant la structure de données réelle.
EDIT: Comme Evan l’a fait remarquer à juste titre, les spinlocks ralentiront une machine à processeur unique. Vous utiliseriez uniquement un verrou tournant sur une boîte multiprocesseur, car sur un processeur unique, le processus contenant le mutex ne le réinitialisera jamais lorsqu'une autre tâche est en cours d'exécution. Les verrous pivotants ne sont utiles que sur les architectures multiprocesseurs.
Bien que mutex et sémaphores soient utilisés comme primitives de synchronisation, il existe une grande différence entre eux. Dans le cas de mutex, seul le thread qui a verrouillé ou acquis le mutex peut le déverrouiller. Dans le cas d'un sémaphore, un thread en attente d'un sémaphore peut être signalé par un autre thread. Certains systèmes d'exploitation prennent en charge l'utilisation de mutex et de sémaphores entre les processus. En règle générale, l’utilisation consiste à créer dans la mémoire partagée.
Mutex: Supposons que le fil de la section critique T1 veut y accéder, puis il suit les étapes ci-dessous. T1:
Sémaphore binaire: il fonctionne sur la base d'une attente et d'un signal de signalisation. wait (s) décroît la valeur "s" de 1 en général, la valeur "s" est initialisée à la valeur "1", le signal (s) augmente la valeur "s" de 1. si "s" est égal à 1, personne n'utilise la section critique; lorsque la valeur est 0, la section critique est utilisée. supposons que le thread T2 utilise une section critique, il suit les étapes ci-dessous. T2:
La différence principale entre Mutex et le sémaphore binaire est dans Mutext si le thread verrouille la section critique puis il doit déverrouiller la section critique, aucun autre thread ne peut le déverrouiller, mais dans le cas d'un sémaphore binaire si un thread verrouille la section critique à l'aide de la fonction wait (s) de s devient "0" et personne ne peut y accéder jusqu'à ce que la valeur de "s" devienne 1 mais supposons que d'autres signaux d'appels de threads signalent la valeur de "s" à 1 et permet à une autre fonction d'utiliser une section critique. par conséquent, dans le fil de sémaphore binaire n'a pas de propriété.
Vous utilisez évidemment mutex pour verrouiller des données dans un thread auquel un autre thread accède en même temps. Supposons que vous veniez d'appeler lock()
et que vous êtes en train d'accéder à des données. Cela signifie que vous ne vous attendez pas à ce qu'un autre thread (ou une autre instance du même code de thread) accède aux mêmes données verrouillées par le même mutex. C'est-à-dire que s'il s'agit du même code de thread qui s'exécute sur une instance de thread différente, frappe le verrou, la lock()
doit alors bloquer le flux de contrôle. Ceci s'applique à un thread qui utilise un code de thread différent, qui accède également aux mêmes données et qui est également verrouillé par le même mutex. Dans ce cas, vous êtes toujours en train d'accéder aux données et vous pouvez prendre, disons, 15 secondes supplémentaires pour atteindre le déverrouillage du mutex (de sorte que l'autre thread bloqué dans le verrouillage du mutex se débloque et permette au contrôle de s'exécuter. accéder aux données). Autorisez-vous à tout prix un autre thread à déverrouiller le même mutex et à son tour, autorisez le thread déjà en attente (bloquant) dans le verrou mutex à débloquer et à accéder aux données? J'espère que tu as ce que je dis ici? Conformément à la définition universelle convenue !,
Donc, si vous êtes très exigeant sur l’utilisation de binaire-sémaphore au lieu de mutex, vous devez alors faire très attention à "délimiter" les verrous et les déverrouiller. Je veux dire que chaque flux de contrôle qui frappe chaque verrou devrait frapper un appel déverrouillé, il ne devrait pas y avoir de "premier déverrouillage", mais plutôt de "premier verrou".
Les mutex sont utilisés pour les "mécanismes de verrouillage". un processus à la fois peut utiliser une ressource partagée
tandis que
Les sémaphores sont utilisés pour les "mécanismes de signalisation" du type "j'ai terminé, je peux continuer"
Sous Windows, il existe deux différences entre les mutex et les sémaphores binaires:
Un mutex ne peut être libéré que par le thread qui en est le propriétaire, c’est-à-dire le thread qui appelait auparavant la fonction Wait (ou qui en a pris possession lors de la création). Un sémaphore peut être libéré par n'importe quel thread.
Un thread peut appeler une fonction d'attente à plusieurs reprises sur un mutex sans bloquer. Cependant, si vous appelez deux fois une fonction wait sur un sémaphore binaire sans le relâcher, le thread se bloquera.
Mythe:
Un couple d'articles dit que "le sémaphore et le mutex binaires sont identiques" ou "le sémaphore de valeur 1 est le mutex", mais la différence fondamentale est que Mutex ne peut être libéré que par le thread qui l'a acquis, alors que vous pouvez signaler un sémaphore à partir de n'importe quel autre thread.
Points clés:
• Un thread peut acquérir plus d'un verrou (Mutex).
• Un mutex ne peut être verrouillé plus d’une fois que s’il s’agit d’un mutex récursif; ici, verrou et déverrouillage pour mutex doivent être identiques.
• Si un thread qui a déjà verrouillé un mutex tente à nouveau de verrouiller le mutex, il entrera dans la liste d'attente de ce mutex, ce qui entraînera un blocage.
• Le sémaphore et le mutex binaires sont similaires mais pas identiques.
• Le Mutex est une opération coûteuse en raison des protocoles de protection qui lui sont associés.
• Le but principal du mutex est d’obtenir un accès atomique ou de verrouiller une ressource.
Un Mutex contrôle l'accès à une seule ressource partagée. Il fournit des opérations pour acquérir () accéder à cette ressource et release () lorsque l'opération est terminée.
A Semaphore contrôle l'accès à un pool de ressources partagé. Il fournit des opérations à Wait () jusqu'à ce que l'une des ressources du pool soit disponible, et à Signal () lorsqu'elle est restituée au pool.
Lorsque le nombre de ressources protégées par un sémaphore est supérieur à 1, il est appelé un sémaphore de comptage. Lorsqu'il contrôle une ressource, il est appelé un sémaphore booléen. Un sémaphore booléen équivaut à un mutex.
Ainsi, un sémaphore est une abstraction de niveau supérieur à Mutex. Un mutex peut être implémenté à l'aide d'un sémaphore, mais pas l'inverse.
La question modifiée est la suivante: quelle est la différence entre un mutex et un sémaphore "binaire" dans "Linux"?
Rép: Les différences sont les suivantes - i) Portée - La portée de mutex se trouve dans un espace adresse de processus qui l’a créé et est utilisée pour la synchronisation des threads. Tandis que le sémaphore peut être utilisé dans l’espace de processus, il peut donc être utilisé pour la synchronisation interprocessus.
ii) Mutex est léger et plus rapide qu'un sémaphore. Futex est encore plus rapide.
iii) Le mutex peut être acquis plusieurs fois par le même thread avec succès, à condition qu'il le libère le même nombre de fois. Un autre thread essayant d’acquérir bloquera. Alors que dans le cas de sémaphore, si le même processus tente de l’acquérir à nouveau, il bloque puisqu’il ne peut être acquis qu’une fois.
Mutex travaille sur le blocage de la région critique, mais Semaphore travaille sur le compte.
Diff entre le sémaphore binaire et le mutex: OWNERSHIP: Les sémaphores peuvent être signalés (publiés) même par un propriétaire non actuel. Cela signifie que vous pouvez simplement poster depuis n'importe quel autre fil, même si vous n'en êtes pas le propriétaire.
Semaphore est une propriété publique en cours, elle peut être simplement postée par un thread non propriétaire. S'il vous plaît marque cette différence en caractères gras, cela signifie beaucoup.
http://www.geeksforgeeks.org/archives/9102 discute en détail.
Mutex
est un mécanisme de verrouillage utilisé pour synchroniser l'accès à une ressource. Semaphore
est le mécanisme de signalisation.
Il appartient au programmeur s’il souhaite utiliser un sémaphore binaire à la place de mutex.
Dans les fenêtres, la différence est la suivante. MUTEX: le processus qui s'exécute avec succès wait doit exécuter un signal et vice versa. BINARY SEMAPHORES: Différents processus peuvent exécuter wait ou signal opération sur un sémaphore.
Outre le fait que les mutex ont un propriétaire, les deux objets peuvent être optimisés pour un usage différent. Les mutex sont conçus pour ne se tenir que pendant une courte période; le non-respect de cette règle peut entraîner de mauvaises performances et une planification injuste. Par exemple, un thread en cours d'exécution peut être autorisé à acquérir un mutex, même si un autre thread est déjà bloqué sur celui-ci. Les sémaphores peuvent offrir plus d'équité, ou l'équité peut être forcée en utilisant plusieurs variables de condition.
Le concept était clair pour moi après être passé par dessus les messages. Mais il y avait quelques questions en suspens. Donc, j'ai écrit ce petit morceau de code.
Lorsque nous essayons de donner un sémaphore sans le prendre, cela passe. Mais, lorsque vous essayez de donner un mutex sans le prendre, il échoue. J'ai testé cela sur une plate-forme Windows. Activez USE_MUTEX pour exécuter le même code à l'aide d'un MUTEX.
#include <stdio.h>
#include <windows.h>
#define xUSE_MUTEX 1
#define MAX_SEM_COUNT 1
DWORD WINAPI Thread_no_1( LPVOID lpParam );
DWORD WINAPI Thread_no_2( LPVOID lpParam );
HANDLE Handle_Of_Thread_1 = 0;
HANDLE Handle_Of_Thread_2 = 0;
int Data_Of_Thread_1 = 1;
int Data_Of_Thread_2 = 2;
HANDLE ghMutex = NULL;
HANDLE ghSemaphore = NULL;
int main(void)
{
#ifdef USE_MUTEX
ghMutex = CreateMutex( NULL, FALSE, NULL);
if (ghMutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
#else
// Create a semaphore with initial and max counts of MAX_SEM_COUNT
ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
if (ghSemaphore == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
#endif
// Create thread 1.
Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL);
if ( Handle_Of_Thread_1 == NULL)
{
printf("Create first thread problem \n");
return 1;
}
/* sleep for 5 seconds **/
Sleep(5 * 1000);
/*Create thread 2 */
Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL);
if ( Handle_Of_Thread_2 == NULL)
{
printf("Create second thread problem \n");
return 1;
}
// Sleep for 20 seconds
Sleep(20 * 1000);
printf("Out of the program \n");
return 0;
}
int my_critical_section_code(HANDLE thread_handle)
{
#ifdef USE_MUTEX
if(thread_handle == Handle_Of_Thread_1)
{
/* get the lock */
WaitForSingleObject(ghMutex, INFINITE);
printf("Thread 1 holding the mutex \n");
}
#else
/* get the semaphore */
if(thread_handle == Handle_Of_Thread_1)
{
WaitForSingleObject(ghSemaphore, INFINITE);
printf("Thread 1 holding semaphore \n");
}
#endif
if(thread_handle == Handle_Of_Thread_1)
{
/* sleep for 10 seconds */
Sleep(10 * 1000);
#ifdef USE_MUTEX
printf("Thread 1 about to release mutex \n");
#else
printf("Thread 1 about to release semaphore \n");
#endif
}
else
{
/* sleep for 3 secconds */
Sleep(3 * 1000);
}
#ifdef USE_MUTEX
/* release the lock*/
if(!ReleaseMutex(ghMutex))
{
printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError());
}
#else
if (!ReleaseSemaphore(ghSemaphore,1,NULL) )
{
printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError());
}
#endif
return 0;
}
DWORD WINAPI Thread_no_1( LPVOID lpParam )
{
my_critical_section_code(Handle_Of_Thread_1);
return 0;
}
DWORD WINAPI Thread_no_2( LPVOID lpParam )
{
my_critical_section_code(Handle_Of_Thread_2);
return 0;
}
Le fait même que le sémaphore vous permette de signaler que "c'est fait en utilisant une ressource", même s'il ne l'a jamais possédée, me fait penser qu'il existe un couplage très lâche entre posséder et signaler dans le cas des sémaphores.
Bien qu'un sémaphore binaire puisse être utilisé en tant que mutex, un mutex est un cas d'utilisation plus spécifique, en ce sens que seul le processus qui a verrouillé le mutex est censé le déverrouiller. Cette contrainte de propriété permet d'assurer une protection contre:
Ces contraintes ne sont pas toujours présentes car elles dégradent la vitesse. Pendant le développement de votre code, vous pouvez activer ces vérifications temporairement.
par exemple. vous pouvez activer l'attribut de contrôle d'erreur dans votre mutex. Une erreur de vérification des mutex retourne EDEADLK
si vous essayez de verrouiller le même deux fois et EPERM
si vous déverrouillez un mutex qui n'est pas le vôtre.
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init (&mutex, &attr);
Une fois initialisé, nous pouvons placer ces contrôles dans notre code comme ceci:
if(pthread_mutex_unlock(&mutex)==EPERM)
printf("Unlock failed:Mutex not owned by this thread\n");
Mutex est utilisé pour protéger le code et les données sensibles, le sémaphore est utilisé pour la synchronisation.Vous pouvez également avoir une utilisation pratique avec protéger le code sensible, mais vous risqueriez peut-être de désactiver la protection par l'autre thread à l'aide de l'opération V.So. La différence entre bi-sémaphore et mutex est la propriété.Par exemple, par toilettes, Mutex est comme on peut entrer dans les toilettes et verrouiller la porte, personne d'autre ne peut entrer jusqu'à ce que l'homme sorte, bi-sémaphore est comme on peut entrer les toilettes et verrouiller la porte, mais quelqu'un d'autre pourrait entrer en demandant à l'administrateur d'ouvrir la porte, c'est ridicule.
Mutex
Les mutex sont généralement utilisés pour sérialiser l'accès à une section de code réentrant qui ne peut pas être exécutée simultanément par plusieurs threads. Un objet mutex n'autorise qu'un seul thread dans une section contrôlée, ce qui oblige les autres threads tentant d'accéder à cette section à attendre que le premier thread se termine. Cette utilisation d'un mutex consiste à protéger une ressource partagée peut avoir un effet dangereux. effet secondaire non intentionnel. Deux RTOS tâches quelconques, qui fonctionnent selon des priorités différentes et se coordonnent via un mutex, créent l'occasion pour inversion des priorités . Mutex fonctionne dans espace utilisateur .
Sémaphore
Le sémaphore est un mécanisme de signalisation. Semaphore limite le nombre d'utilisateurs simultanés d'une ressource partagée à un nombre maximal. Les threads peuvent demander l'accès à la ressource (décrémenter le sémaphore) et peuvent signaler qu'ils ont fini d'utiliser la ressource (incrémenter le sémaphore). Il permet à un nombre de threads d'accéder aux ressources partagées. L'utilisation correcte d'un sémaphore sert à la signalisation d'une tâche à une autre.maphores peut également être utilisé pour signaler depuis une routine de service d'interruption (ISR) à une tâche. La signalisation d'un sémaphore est un comportement non bloquant RTOS et par conséquent, protégé contre les ISR. Parce que cette technique élimine la nécessité de désactiver les interruptions au niveau de la tâche, sujet aux erreurs. Cela fonctionne dans espace noyau .
Les mutex ont la propriété, contrairement aux sémaphores. Bien que n'importe quel thread, dans la portée d'un mutex, puisse obtenir un mutex non verrouillé et verrouiller l'accès à la même section critique de code, uniquement le thread qui a verrouillé un mutex devrait = le déverrouille .
La réponse peut dépendre du système d'exploitation cible. Par exemple, au moins une implémentation RTOS que je connais bien autorisera plusieurs opérations "get" séquentielles sur un seul mutex de système d'exploitation, à condition qu'elles proviennent toutes du même contexte de thread. Les multiples gets doivent être remplacés par un nombre égal de put avant qu'un autre thread puisse obtenir le mutex. Ceci diffère des sémaphores binaires, pour lesquels un seul get est autorisé à la fois, quel que soit le contexte du thread.
L'idée derrière ce type de mutex est que vous protégez un objet en permettant uniquement à un seul contexte de modifier les données à la fois. Même si le thread obtient le mutex et appelle ensuite une fonction qui modifie davantage l'objet (et obtient/place le mutex protecteur autour de ses propres opérations), les opérations doivent toujours être sécurisées, car elles se déroulent toutes sous un seul thread.
{
mutexGet(); // Other threads can no longer get the mutex.
// Make changes to the protected object.
// ...
objectModify(); // Also gets/puts the mutex. Only allowed from this thread context.
// Make more changes to the protected object.
// ...
mutexPut(); // Finally allows other threads to get the mutex.
}
Bien sûr, lorsque vous utilisez cette fonctionnalité, vous devez être certain que tous les accès d’un même thread sont vraiment sécurisés!
Je ne sais pas si cette approche est courante ou si elle s'applique en dehors des systèmes avec lesquels je suis familier. Pour un exemple de ce type de mutex, voir le RTOS ThreadX.
Comme de nombreuses personnes ici mentionnées, un mutex est utilisé pour protéger un élément de code critique (section critique AKA). Vous allez acquérir le mutex (verrouiller), entrer dans la section critique et relâcher mutex (déverrouiller)tous dans le même fil.
Lorsque vous utilisez un sémaphore, vous pouvez faire en sorte qu'un thread attende sur un sémaphore (par exemple, le thread A), jusqu'à ce qu'un autre thread (par exemple, le thread B) termine la tâche, puis configure le Sémaphore pour que le thread A arrête l'attente et continue sa tâche.
Le problème de base est la concurrence. Il y a plus d'un flux de contrôle. Pensez à deux processus utilisant une mémoire partagée. Désormais, un seul processus peut accéder à la mémoire partagée à la fois. Si plusieurs processus accèdent à la mémoire partagée à la fois, le contenu de la mémoire partagée serait corrompu. C'est comme une voie ferrée. Un seul train peut y circuler, sinon il y aurait un accident. Il existe donc un mécanisme de signalisation contrôlé par le conducteur. Si le signal est vert, le train peut partir et s'il est rouge, il doit attendre pour pouvoir utiliser la voie. De même, en cas de mémoire partagée, il existe un sémaphore binaire. Si le sémaphore est 1, un processus l'acquiert (le rend 0) et continue et y accède. Si le sémaphore est 0, le processus attend. La fonctionnalité que doit fournir le sémaphore binaire est l'exclusion mutuelle (ou mutex, en bref), de sorte qu'une seule des nombreuses entités simultanées (processus ou thread) en exclut d'autres. C'est un avantage que nous ayons des sémaphores de comptage, qui aident à la synchronisation de plusieurs instances d'une ressource.
L'exclusion mutuelle est la fonctionnalité de base fournie par les sémaphores. Maintenant, dans le contexte des threads, nous pourrions avoir un nom et une syntaxe différents pour cela. Mais le concept sous-jacent est le même: comment conserver l’intégrité du code et des données dans la programmation simultanée. À mon avis, des éléments tels que la propriété et les contrôles associés sont des améliorations apportées par les implémentations.
Le mutex et le sémaphore binaire ont le même usage, mais en réalité, ils sont différents.
En cas de mutex, seul le thread qui l'a bloqué peut le déverrouiller. Si un autre thread vient le verrouiller, il attendra.
En cas de sémaphone, ce n'est pas le cas. Semaphore n'est pas lié à un ID de thread particulier.
"binaire sémaphore" est un langage de programmation permettant d'éviter un "sémaphore" comme "mutex". Apparemment, il y a deux très grandes différences:
La façon dont vous appelez chacun d'eux.
La longueur maximale de "l'identifiant".