Custom sleep conditional variable sleep instance in C++

  • 2020-04-02 03:01:42
  • OfStack

It goes without saying that sleep works, and almost every language provides similar functions that are easy to call. Sleep does nothing more than make a program wait a certain amount of time, and there are many ways to do this. The simplest is often the roughest. Here's an example.


 
#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <signal.h> 
 
class TestServer 

public: 
    TestServer() : run_(true) {}; 
    ~TestServer(){}; 
 
    void Start() 
    { 
        pthread_create(&thread_, NULL, ThreadProc, (void*)this); 
    } 
    void Stop() 
    { 
        run_ = false; 
    } 
    void Wait() 
    { 
        pthread_join(thread_, NULL); 
    } 
    void Proc() 
    { 
        int count = 0; 
        while (run_) 
        { 
            printf("sleep count:%dn", ++count); 
            sleep(5); 
        } 
    } 
 
private: 
    bool run_; 
    pthread_t thread_; 
 
    static void* ThreadProc(void* arg) 
    { 
        TestServer* me = static_cast<TestServer*>(arg); 
        me->Proc(); 
        return NULL; 
    } 
}; 
 
TestServer g_server; 
 
void StopService() 

    g_server.Stop(); 

 
void StartService() 

    g_server.Start(); 
    g_server.Wait(); 

 
void SignalHandler(int sig) 

    switch(sig) 
    { 
        case SIGINT: 
            StopService(); 
        default: 
            break; 
    } 

 
int main(int argc, char* argv[]) 

    signal(SIGINT, SignalHandler); 
    StartService(); 
    return 0; 


This code describes a simple service program, in order to simplify the service we omit the processing logic, that is, the content of the Proc function, here we just periodically print a statement, in order to achieve the purpose of periodicity, we use sleep to achieve, every 5 seconds to print. In the main function we capture the SIGINT signal, and when the program starts at the terminal, if you enter CTR +c, this will send an interrupt signal to the program, and generally the program will exit, and here we capture this signal, and we do it in our own logic, which is to call the server's Stop function. Execute the compile command

$ g++ test.cpp -o test -lpthread 

Then the terminal input. / test to run the program, the program every 5 seconds will print out a statement on the screen, press the CTL + c, you will find that the program did not immediately exits, but wait for a while to exit, investigate its reason, when press the CTL + c signal interruption, the procedure to capture and implement their own logic, is also called the Stop function of the server, run the flag bit run_ is set to false, the Proc function detect run_ to false exit the loop and end of the program, But it's possible (and I should say most of the time) that the Proc will execute right up to the point of sleep, where the program is suspended, and because we've caught the interrupt, it won't quit, but will continue to be suspended until the time is up. This sleep is obviously not very elegant, so here are two ways to exit quickly.

Custom sleep

When we call the system to provide the sleep that we are unable to do other things within the function, based on this we grew out of an idea, if can detect exit in the sleep variables, wouldn't it be pulled out of the can be quickly, yes, it is like this, through the custom sleep, we will split time slice into smaller pieces, every other segment detection time, so you can exit the delay time of the procedure with the smaller for the smaller fragments, custom sleep is as follows


void sleep(int seconds, const bool* run) 

    int count = seconds * 10; 
    while (*run && count > 0) 
    { 
        --count; 
        usleep(100000); 
    } 


It is important to note that the second parameter of this sleep must be of pointer type, because we need to detect its real time value, not just use its incoming value, and the corresponding function call has to be slightly modified. The full code is as follows

 
#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <signal.h> 
 
class TestServer 

public: 
    TestServer() : run_(true) {}; 
    ~TestServer(){}; 
 
    void Start() 
    { 
     pthread_create(&thread_, NULL, ThreadProc, (void*)this); 
    } 
 
    void Stop() 
    { 
       run_ = false; 
    } 
 
    void Wait() 
    { 
        pthread_join(thread_, NULL); 
    } 
 
    void Proc() 
    { 
        int count = 0; 
        while (run_) 
        { 
            printf("sleep count:%dn", ++count); 
            sleep(5, &run_); 
        } 
    } 
 
private: 
    bool run_; 
    pthread_t thread_; 
 
    void sleep(int seconds, const bool* run) 
    { 
        int count = seconds * 10; 
        while (*run && count > 0) 
        { 
            --count; 
            usleep(100000); 
 
        } 
    } 
 
    static void* ThreadProc(void* arg) 
    { 
        TestServer* me = static_cast<TestServer*>(arg); 
        me->Proc(); 
        return NULL; 
    } 
}; 
 
TestServer g_server; 
 
void StopService() 

   g_server.Stop(); 

 
void StartService() 

    g_server.Start(); 
   g_server.Wait(); 

 
void SignalHandler(int sig) 

    switch(sig) 
    { 
        case SIGINT: 
            StopService(); 
        default: 
            break; 
    } 

 
int main(int argc, char* argv[]) 

    signal(SIGINT, SignalHandler); 
    StartService(); 
    return 0; 

Compile g++ test2.cpp-o test, run./test. When the program starts, press CTL +c to see if the program exits quickly.

In fact, this exit does not exit immediately, but divides the waiting time of sleep into smaller time slices, the previous example is 0.1 seconds, which means that after pressing CTR +c, the program will actually delay from 0 to 0.1 seconds before exiting, but this time is so short that it looks like exiting immediately.

Implement sleep with the condition variable

The general idea is that, in the loop when waiting for a condition variable, and set the timeout, if there are other threads within the time triggered condition variables, waiting exit immediately, otherwise you will wait until the set time, so that you can pass on the condition variable to achieve the control of sleep, and can be in need of exit immediately.

Condition variables, often and mutex collocation is used, the mutex logic is simple, if a thread to obtain the mutex, other threads are not available, that is to say, if two threads execute simultaneously to pthread_mutex_lock statements, only one thread executes complete, and another thread can block, until there is thread calls pthread_mutex_unlock will continue to perform. So we tend to use mutex when multiple threads access the same memory area to prevent multiple threads from modifying a memory area at the same time. This example USES the following functions, mutex - related functions


int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); 
int pthread_mutex_lock(pthread_mutex_t *mutex); 
int pthread_mutex_unlock(pthread_mutex_t *mutex); 
int pthread_mutex_destroy(pthread_mutex_t *mutex); 

The above functions are initialization, locking, unlocking and destruction. The conditional variable correlation function has


int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); 
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); 
int pthread_cond_signal(pthread_cond_t *cond); 
int pthread_cond_destroy(pthread_cond_t *cond); 

The above functions are initialization, timeout waiting condition variable, trigger condition variable and destroy. The pthread_cond_timedwait and pthread_cond_signal functions need to be explained


pthread_cond_timedwait

This function will block after the call, which is similar to sleep, but it will wake up in two situations: 1. 2. When system time reaches abstime, note that this is absolute time, not relative time. Its advantage over sleep is in the first place. Another parameter is mutex. When this function is executed, its effect is equivalent to locking the mutex at the entrance of the function and then unlocking the mutex at the exit. When there are multiple threads calling this function, it can be understood in this way

pthread_cond_signal
It has only one parameter cond, which is very simple, which is to trigger the thread waiting for cond, notice that it will only trigger one at a time, if you want to trigger all the counties waiting for cond, you need to use the pthread_cond_broadcast function, the parameters and usage are the same

With the above background knowledge, you can implement sleep more elegantly, mainly focusing on the Proc function and Stop function, the complete code is as follows


 
#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <signal.h> 
#include <sys/time.h> 
 
class TestServer 

public: 
    TestServer() : run_(true)  
    { 
        pthread_mutex_init(&mutex_, NULL); 
        pthread_cond_init(&cond_, NULL); 
    }; 
    ~TestServer() 
    { 
        pthread_mutex_destroy(&mutex_); 
        pthread_cond_destroy(&cond_); 
    }; 
 
    void Start() 
    { 
        pthread_create(&thread_, NULL, ThreadProc, (void*)this); 
    } 
 
    void Stop() 
    { 
        run_ = false; 
        pthread_mutex_lock(&mutex_); 
        pthread_cond_signal(&cond_); 
        pthread_mutex_unlock(&mutex_); 
   } 
 
    void Wait() 
    { 
        pthread_join(thread_, NULL); 
    } 
 
    void Proc() 
    { 
        pthread_mutex_lock(&mutex_); 
        struct timeval now; 
        int count = 0; 
        while (run_) 
        { 
            printf("sleep count:%dn", ++count); 
            gettimeofday(&now, NULL); 
            struct timespec outtime; 
            outtime.tv_sec = now.tv_sec + 5; 
            outtime.tv_nsec = now.tv_usec * 1000; 
            pthread_cond_timedwait(&cond_, &mutex_, &outtime); 
        } 
        pthread_mutex_unlock(&mutex_); 
    } 
 
private: 
    bool run_; 
    pthread_t thread_; 
    pthread_mutex_t mutex_; 
    pthread_cond_t cond_; 
 
    static void* ThreadProc(void* arg) 
    { 
        TestServer* me = static_cast<TestServer*>(arg); 
        me->Proc(); 
        return NULL; 
    } 
}; 
 
TestServer g_server; 
 
void StopService() 

    g_server.Stop(); 

 
void StartService() 

    g_server.Start(); 
    g_server.Wait(); 

 
void SignalHandler(int sig) 

    switch(sig) 
    { 
        case SIGINT: 
            StopService(); 
        default: 
            break; 
    } 

 
int main(int argc, char* argv[]) 

    signal(SIGINT, SignalHandler); 
    StartService(); 
    return 0; 

Just like test2.cpp, the program is run after compilation and prints a line of output on the screen every 5 seconds. Enter CTR +c and the program exits immediately


Related articles: