Suspendre Thread sur Linux (version corrigée en bas de l'article)

Puisqu'il n'y avait pas d'API de type Suspend Thread sous Linux, essayez de suspendre / reprendre le thread avec mutex.

Pour le moment, je l'ai implémenté deux fois, mais j'ai souligné que je n'ai pas beaucoup de connaissances sur l'implémentation de l'API OS, donc je l'ai mangé deux fois, donc j'en suis fou, alors je me demande si c'est la troisième fois pour être honnête ou s'il y en a deux.

Résumé des points à signaler jusqu'à présent

Points de @drab

  1. Vous pouvez utiliser "pthread_cond_wait" ou "fifo ou file d'attente de messages"
  2. L'utilisation de pthread_cond_wait dans le code qui fait quelque chose avec un événement de frappe est susceptible d'être terminée

Points à souligner par @ angel_p_57

  1. Ne relâchez jamais le mutex des autres threads.
  2. Il y a un malentendu sur la façon d'utiliser pthread_cond_ * (c'est NG de l'utiliser juste pour attendre un tel événement!)

Sur la base de ces points, ce que je voulais faire en premier lieu.

Lors de la mise en œuvre du traitement des messages ou quelque chose comme ça Lorsque vous souhaitez traiter en continu les messages de la file d'attente après les avoir mis dans la file d'attente (en bref, un traitement asynchrone tel que l'envoi vers le nord-ouest).

Je veux suspendre le fil à un moment donné, car c'est un gaspillage de ressources qui font une boucle inutile quand il n'y a pas de message. Bref, je veux attendre l'événement.

Comparez ce que vous avez souligné avec ce que vous voulez faire

Fait remarquer: l'utilisation de pthread_cond_wait dans le code qui fait quelque chose avec un événement de frappe est susceptible d'être terminée Ce que je veux faire: je veux attendre un événement.

En dehors.

~~ Un mémo pour mettre en pause l'utilisation de Mutex dans un tel cas. ~~

~~ ** 2017/04/17 Je l'ai écrit avec la méthode de mise en œuvre correcte selon le sujet signalé. (Voir le bas de l'article) ** ~~ ** 2017/04/21 Corrigé à nouveau **

Décoder plein d'erreurs que j'ai écrites au début

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
#include <unistd.h>
#include <stdarg.h>
#include<stdint.h>
#include<assert.h>

//Mettez une chaîne sur la console
int consoleWrite(const char *fmt, ...)
{
    va_list list;
    va_start(list, fmt);
    int writed = vprintf(fmt, list);
    fflush(stdout);
    va_end(list);
    return writed;
}

//Accepter les chaînes du clavier
size_t input(char *buf, size_t bufLen)
{
#define GabageBufSize 0x100
    uint8_t bin[GabageBufSize];
    char *savePtr = NULL;
    char *token = NULL;
    static_assert(sizeof(bin) == GabageBufSize, "Gabage buffer size not 255");

    fgets(buf, bufLen, stdin);
    token = strchr(buf, '\n');
    if (token != NULL)
    {
        *token = '\0';
    }
    else
    {
        buf[bufLen - 1] = '\0';
        while (token == NULL)
        {
            fgets(bin, GabageBufSize, stdin);
            token = strchr(bin, '\n');
            if (token != NULL)
            {
                break;
            }
        }
    }
    return strlen(buf);
}

//C'est une mauvaise implémentation
void suspend(pthread_mutex_t* lock)
{
    pthread_mutex_trylock(lock);
//S'il n'a jamais été verrouillé, il sera verrouillé ici
    pthread_mutex_lock(lock);
    pthread_mutex_unlock(lock);
}

void *messageSender(void *lock)
{
    int count = 1;
    while (true)
    {
        consoleWrite(".");
        sleep(1);
        if ((count % 3) == 0)
        {
            //Ici, attendez que l'événement se produise.
            suspend((pthread_mutex_t*)lock);
        }
        count++;
    }
}

int main(int argc, char *argv[])
{
    pthread_t tid;
    pthread_mutex_t lock;
    char buf[32];
    pthread_mutex_init(&lock, NULL);
    pthread_create(&tid, NULL, messageSender, &lock);
    while (true)
    {
        input(buf, 32);
        pthread_mutex_unlock(&lock); //L'opération de déverrouillage n'est pas garantie par les autres threads.
        consoleWrite("unlocked.\n");
    }
    pthread_join(tid, NULL);
}

~~ Lorsque les données arrivent dans la file d'attente, utilisez le rappel et appuyez sur pthread_mutex_unlock ~~ Le déverrouillage de l'objet ~~ Mutex redémarre le thread. ~~ ~~ Dans la démo ci-dessus, la partie où les données sont stockées dans la file d'attente est remplacée par l'entrée du clavier. ~~

~~ Je l'ai implémenté aussi longtemps que je pouvais le faire sans penser aux performances, donc ~~ ~~ Si vous avez d'autres bonnes idées, faites-le. ~~ J'écrirai un exemple en utilisant pthread_cond_wait dans un autre article à une date ultérieure.


Encore plus de mauvaise implémentation à partir d'ici

Référence: Section: Fonctions de la bibliothèque C de la page de manuel (3) PTHREAD_COND

  1. pthread_cond_wait prend cond (= condition: variable de condition) et mutex comme arguments
  2. L'objet mutex transmis à pthread_cond_wait doit être verrouillé
  3. Les threads arrêtés par pthread_cond_wait sont redémarrés par pthread_cond_signal
//Différence de correction uniquement

typedef struct Suspend
{
    pthread_mutex_t lockMutex;
    pthread_cond_t lockCond;
} Suspend;

void suspend(Suspend *lock)
{
//Mauvaise utilisation
    pthread_mutex_trylock(&lock->lockMutex);
    pthread_cond_wait(&lock->lockCond,&lock->lockMutex);
    pthread_mutex_unlock(&lock->lockMutex);
}

void SuspendInit(Suspend *lock)
{
    pthread_cond_init(&lock->lockCond, NULL);
    pthread_mutex_init(&lock->lockMutex, NULL);
}

int main(int argc, char *argv[])
{
    pthread_t tid;
    Suspend lock;
    char buf[32];

    SuspendInit(&lock);
    pthread_create(&tid, NULL, messageSender, &lock);
    while (true)
    {
        input(buf, 32);
        pthread_cond_signal(&lock.lockCond);
        consoleWrite("unlocked.\n");
    }
    pthread_join(tid, NULL);
}

~~ Tout d'abord, je sens que j'ai fixé les points signalés. ~~

J'ai l'impression d'avoir pu le réparer ← C'était grâce à mon esprit. Réimplémenté avec pipe (renommé de Suspend stuff en EventInfo stuff)

typedef struct EventInfo
{
    int state;
    int read;
    int write;
    pthread_mutex_t mutex;
} EventInfo;

#define EventInfo_WAIT_BUSY 0
#define EventInfo_WAIT_READY 1

//Attendez que l'événement se produise
void EventInfoWait(EventInfo *lock)
{
    uint8_t msg;
    pthread_mutex_lock(&lock->mutex);
    lock->state = EventInfo_WAIT_READY;
    pthread_mutex_unlock(&lock->mutex);
    int r = read(lock->read, &msg, sizeof(uint8_t));
}

//ne fais rien
void EventInfoRaisingEvent_None(EventInfo *lock)
{
}
//Avisez seulement.
void EventInfoRaisingEvent_Send(EventInfo *lock)
{
    static uint8_t msg = 0xdeadbeef;
    write(lock->write, &msg, sizeof(uint8_t));
}
//Organisez un événement
void EventInfoRaisingEvent(EventInfo *lock)
{
    static void (*EventInfoWakeupSendMessage[2])(EventInfo * lock) =
        {
            EventInfoWakeupSendMessage_None,
            EventInfoWakeupSendMessage_Send};
    pthread_mutex_lock(&lock->mutex);
    EventInfoWakeupSendMessage[lock->state](lock);
    lock->state = EventInfo_WAIT_BUSY;
    pthread_mutex_unlock(&lock->mutex);
}

void *messageSender(void *lock)
{
    int count = 1;
    while (true)
    {
        consoleWrite(".");
        sleep(1);
        if ((count % 3) == 0)
        {
            //Ici, attendez que l'événement se produise.
            EventInfoWait((EventInfo *)lock);
        }
        count++;
    }
}

int EventInfoInit(EventInfo *lock)
{
    int pfd[2];
    int r = pipe(pfd);
    if (r != 0)
    {
        return -1;
    }
    lock->state = EventInfo_WAIT_BUSY;
    fcntl(pfd[1], F_SETFL, O_NONBLOCK);
    lock->read = pfd[0];
    lock->write = pfd[1];
    pthread_mutex_init(&lock->mutex, NULL);
    return 0;
}

int main(int argc, char *argv[])
{
    pthread_t tid;
    EventInfo lock;
    char buf[32];

    EventInfoInit(&lock);
    pthread_create(&tid, NULL, messageSender, &lock);
    while (true)
    {
        input(buf, 32);
        EventInfoRaisingEvent(&lock);
        consoleWrite("unlocked.\n");
    }
    pthread_join(tid, NULL);
    return 0;
}

Correctif, peut-être que cela devrait convenir car cela atteindra l'objectif initial.

Recommended Posts

Suspendre Thread sur Linux (version corrigée en bas de l'article)
Mettez la dernière version de Python dans Linux (Debian) du Chromebook
Installez la dernière version de Git sur votre serveur Linux
L'histoire de l'exécution de l'application asp.net core 3.1 sur la version arm64 Amazon Linux 2
[2020July] Vérifiez l'UDID de l'iPad sous Linux
Utilisez la dernière version de PyCharm sur Ubuntu
Au moment de la mise à jour de python avec ubuntu
Installez la dernière version de CMake sur Ubuntu 18.04.4 LTS
Ouvrez la version Chrome de LINE à partir de la ligne de commande [Linux]
Vérifiez le type et la version de la distribution Linux
Annonce de la disponibilité de Java 11 LTS sur Amazon Linux 2
Notes sur la version de CUDA, cuDNN où tensorflow-gpu fonctionnait
Commandes et fichiers pour vérifier la version de CentOS Linux
Obtenez le nom d'hôte du PC hôte avec Docker sous Linux
Aligner la version de chromedriver_binary
Installez JDK sur Linux
Collez le lien sous Linux
[Dernière version] Faites parler le bot à intervalles réguliers avec discord.py
Sous Linux, l'horodatage d'un fichier est un peu dépassé.
Comment mettre à jour la version Python de Cloud Shell dans GCP
Tester la version du module argparse
Achèvement de la commande docker sous Linux
pyenv-changer la version python de virtualenv
Installez la dernière version d'Apache httpd 2.4 à partir des sources sur Cent OS 8
[Java] [Linux] Etude de la manière dont l'implémentation des processus enfants Java sous Linux est réalisée
J'ai essayé de mesurer le temps d'attente de la file d'attente d'exécution d'un processus sous Linux
Version 2019: analyse des tendances des accès non autorisés (exemple de serveur polyvalent sur le cloud)
Folding @ Home sur Linux Mint pour contribuer à l'analyse du nouveau virus corona
Résumez le titre de Hottentori dans Hateb et regardez le présent du Web