程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++中自界說sleep、前提變量sleep實例

C++中自界說sleep、前提變量sleep實例

編輯:關於C++

C++中自界說sleep、前提變量sleep實例。本站提示廣大學習愛好者:(C++中自界說sleep、前提變量sleep實例)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中自界說sleep、前提變量sleep實例正文


sleep的感化無需多說,簡直每種說話都供給了相似的函數,挪用起來也很簡略。sleep的感化不過是讓法式期待若干時光,而為了到達如許的目標,其實有許多種方法,最簡略的常常也是最粗魯的,我們就以上面這段代碼來舉例解釋(注:本文說起的法式編譯運轉情況為Linux)

/* filename: test.cpp */ 
#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:%d\n", ++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; 


這段代碼描寫了一個簡略的辦事法式,為了簡化我們省略了辦事的處置邏輯,也就是Proc函數的內容,這裡我們只是周期性的打印某條語句,為了到達周期性的目標,我們用sleep來完成,每隔5秒鐘打印一次。在main函數中我們對SIGINT旌旗燈號停止了捕獲,當法式在終端啟動以後,假如你輸出ctr+c,這會向法式發送中止旌旗燈號,普通來講法式會加入,而這裡我們捕獲到了這個旌旗燈號,會按我們本身的邏輯來處置,也就是挪用server的Stop函數。履行編譯敕令

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

然後在終端輸出./test運轉法式,這時候法式每隔5秒會在屏幕上打印一條語句,按下ctl+c,你會發明法式並沒有立刻加入,而是期待了一會兒才加入,究其緣由,當按下ctl+c收回中止旌旗燈號時,法式捕獲到並履行本身的邏輯,也就是挪用了server的Stop函數,運轉標志位run_被置為false,Proc函數檢測到run_為false則加入輪回,法式停止,但有能夠(應當說年夜多半情形都是如斯)此時Proc正好履行到sleep那一步,而sleep是將法式掛起,因為我們捕獲到了中止旌旗燈號,是以它不會加入,而是持續掛起直到時光知足為止。這個sleep明顯顯得不敷優雅,上面引見兩種能疾速加入的方法。

自界說sleep

在我們挪用體系供給的sleep時我們是沒法在函數外部做其它工作的,基於此我們就萌發出一種設法主意,假如在sleep中可以或許檢測到加入變量,那豈不是就可以疾速加入了,沒錯,工作就是如許子的,經由過程自界說sleep,我們將時光片朋分成更小的片斷,每隔一個片斷檢測一次,如許就可以將法式的加入延遲時光減少為這個更小的片斷,自界說的sleep以下

void sleep(int seconds, const bool* run) 

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


須要留意的是,這個sleep的第二個參數必需是指針類型的,由於我們須要檢測到它的及時值,而不只是應用它傳入出去的值,響應的函數挪用也得稍作修正,完全的代碼以下

/* filename: test2.cpp */ 
#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:%d\n", ++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; 

編譯g++ test2.cpp -o test,運轉./test,當法式啟動以後按ctl+c,看法式是否是很快就加入了。

其實這類加入其實不是立馬加入,而是將sleep的期待時光分紅了更小的時光片,上例是0.1秒,也就是說在按下ctr+c以後,法式其實還會延時0到0.1秒才會加入,只不外這個時光很短,看上去就像立馬加入一樣。

用前提變量完成sleep

年夜致的思惟就是,在輪回時期待一個前提變量,並設置超不時間,假如在這個時光以內有其它線程觸發了前提變量,期待會立刻加入,不然會一向比及設置的時光,如許便可以經由過程對前提變量的掌握來完成sleep,而且可以在須要的時刻立馬加入。

前提變量常常會和互斥鎖搭配應用,互斥鎖的邏輯很簡略,假如一個線程獲得了互斥鎖,其它線程就沒法獲得,也就是說假如兩個線程同時履行到了pthread_mutex_lock語句,只要一個線程會履行完成,而另外一個線程會壅塞,直到有線程挪用pthread_mutex_unlock才會持續往下履行。所以我們常常在多線程拜訪統一內存區域時會用到互斥鎖,以避免多個線程同時修正某一塊內存區域。本例用到的函數有以下幾個,互斥鎖相干函數有

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); 

以上函數功效分離是初始化、加鎖、解鎖、燒毀。前提變量相干函數有


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); 

以上函數功效分離是初始化、超時期待前提變量、觸發前提變量、燒毀。這裡須要說明一下pthread_cond_timedwait和pthread_cond_signal函數

pthread_cond_timedwait

這個函數挪用以後會壅塞,也就是相似sleep的感化,然則它會在兩種情形下被叫醒:1、前提變量cond被觸發時;2、體系時光達到abstime時,留意這裡是相對時光,不是絕對時光。它比sleep的高超的地方就在第一點。別的它還有一個參數是mutex,當履行這個函數時,它的後果同等於在函數進口處先對mutex加鎖,在出口處再對mutex解鎖,當有多線程挪用這個函數時,可以按這類方法去懂得

pthread_cond_signal
它只要一個參數cond,感化很簡略,就是觸發期待cond的線程,留意,它一次只會觸發一個,假如要觸發一切期待cond的縣城,須要用到pthread_cond_broadcast函數,參數和用法都是一樣的

有了以上配景常識,便可以加倍優雅的完成sleep,重要存眷Proc函數和Stop函數,完全的代碼以下


/* filename: test3.cpp */ 
#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:%d\n", ++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; 

和test2.cpp一樣,編譯以後運轉,法式每隔5秒在屏幕打印一行輸入,輸出ctr+c,法式會立馬加入

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved