Search code examples
c++multithreadingmutexunique-lock

unique lock is not unlocking inside while(1)


In the next code the std::unique_lock lck is not unlocked in Manager::CommandShell, despite being explicitly unlocked. I'm able to get "Entering lock" but not "Inside lock", does anybody knows why unlock is not working? Or perhaps it is and it doesen't work as I thought?

std::mutex stdinMutex;
Manager *pman=NULL;

void *StdIn_Reader(void *p)
{
    int nbytes; 

    while(1)    /// Infinite loop
    {
        std::unique_lock<std::mutex> lck{stdinMutex};
        nbytes = read(0,pman->stdin_command,MAXCLIENTMSG);
        if (nbytes > 0)
        {
            pman->stdin_command[nbytes]='\0';
            /// Signal cmd
            pthread_kill(pman->self_id,SIGUSR2);
        }
        lck.unlock();
    }
    return NULL;
}

bool Manager::CommandShell(bool started)
{
    char command[(MAXCLIENTMSG+1)*MAXNUMCOMMANDS];
    // variables to process more than one order in a message (when it happens)

    sigset_t newmask;
    siginfo_t info;
    int rcvd_sig;

    // Mask for block all but SIGUSR1 and SIGUSR2 signals
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGUSR1);
    sigaddset(&newmask, SIGUSR2);

    pthread_sigmask(SIG_BLOCK, &newmask, NULL);

    while (1)
    {
        do{
            rcvd_sig = sigwaitinfo(&newmask, &info);
        }while(rcvd_sig==-1);

        command[0]='\0';

        {   
            cout << "Entering lock\n";
            std::unique_lock<std::mutex> lck{stdinMutex};   
            cout << "Inside lock\n";
            if(strlen(stdin_command)){
                    strcpy(command+strlen(command),stdin_command);
                }
                stdin_command[0]='\0'; 
            }
            lck.unlock();
        }
    }
}

Solution

  • In general holding a mutex lock whilst performing a blocking operation like read will lead to deadlocks.

    The easiest solution for your code is likely to read into a temporary buffer then lock the mutex and copy into your data structure:

        while(1)    /// Infinite loop
        {
            char temp[MAXCLIENTMSG];
            nbytes = read(0,temp,MAXCLIENTMSG);
            if (nbytes > 0)
            {
                std::unique_lock<std::mutex> lck{stdinMutex};
                memcpy(pman->stdin_command, temp, nbytes)
                pman->stdin_command[nbytes]='\0';
                /// Signal cmd
                pthread_kill(pman->self_id,SIGUSR2);
            }
        }