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,法式會立馬加入