chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

定時(shí)器的實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)選擇

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-13 14:22 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在后端的開(kāi)發(fā)中,定時(shí)器有很廣泛的應(yīng)用。

比如:

心跳檢測(cè)

倒計(jì)時(shí)

游戲開(kāi)發(fā)的技能冷卻

redis的鍵值的有效期等等,都會(huì)使用到定時(shí)器。

定時(shí)器的實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)選擇

紅黑樹(shù)

對(duì)于增刪查,時(shí)間復(fù)雜度為O(logn),對(duì)于紅黑樹(shù)最?節(jié)點(diǎn)為最左側(cè)節(jié)點(diǎn),時(shí)間復(fù)雜度O(logn)

最小堆

對(duì)于增查,時(shí)間復(fù)雜度為O(logn),對(duì)于刪時(shí)間復(fù)雜度為O(n),但是可以通過(guò)輔助數(shù)據(jù)結(jié)構(gòu)( map 或者h(yuǎn)ashtable來(lái)快速索引節(jié)點(diǎn))來(lái)加快刪除操作;對(duì)于最?節(jié)點(diǎn)為根節(jié)點(diǎn),時(shí)間復(fù)雜度為O(1)

跳表

對(duì)于增刪查,時(shí)間復(fù)雜度為O(logn),對(duì)于跳表最?節(jié)點(diǎn)為最左側(cè)節(jié)點(diǎn),時(shí)間復(fù)雜度為O(1),但是空間復(fù)雜度?較?,為O(1.5n)

時(shí)間輪

對(duì)于增刪查,時(shí)間復(fù)雜度為O(1),查找最?節(jié)點(diǎn)也為O(1)

libco的使用了時(shí)間輪的實(shí)現(xiàn)

首先,時(shí)間輪有幾個(gè)結(jié)構(gòu),必須理清他們的關(guān)系。

struct stTimeoutItem_t
{
	enum { eMaxTimeout = 40 * 1000 };	// 40s
	stTimeoutItem_t* pPrev;				// 前
	stTimeoutItem_t* pNext;				// 后
	stTimeoutItemLink_t* pLink;			// 鏈表,沒(méi)有用到,寫(xiě)這里有毛用

	OnPreparePfn_t pfnPrepare;			// 不是超時(shí)的事件的處理函數(shù)
	OnProcessPfn_t pfnProcess;			// resume協(xié)程回調(diào)函數(shù)

	void* pArg;							// routine 協(xié)程對(duì)象指針
	bool bTimeout;						// 是否超時(shí)
	unsigned long long ullExpireTime;	// 到期時(shí)間
};

struct stPoll_t;
struct stPollItem_t : public stTimeoutItem_t
{
	struct pollfd* pSelf;			// 對(duì)應(yīng)的poll結(jié)構(gòu)
	stPoll_t* pPoll;				// 所屬的stPoll_t
	struct epoll_event stEvent;		// epoll事件,poll轉(zhuǎn)換過(guò)來(lái)的
};

// co_poll_inner 創(chuàng)建,管理這多個(gè)stPollItem_t
struct stPoll_t : public stTimeoutItem_t
{
	struct pollfd* fds;				// poll 的fd集合
	nfds_t nfds;					// poll 事件個(gè)數(shù)
	stPollItem_t* pPollItems;		// 要加入epoll 事件
	int iAllEventDetach;			// 如果處理過(guò)該對(duì)象的子項(xiàng)目pPollItems,賦值為1
	int iEpollFd;					// epoll fd句柄
	int iRaiseCnt;					// 此次觸發(fā)的事件數(shù)
};

我把這幾個(gè)結(jié)構(gòu)拉一起了,

圖片

其中,能看出,stCoEpool_t管理了這一切

// TimeoutItem的鏈表
struct stTimeoutItemLink_t
{
	stTimeoutItem_t* head;
	stTimeoutItem_t* tail;
};

// TimeOut 
struct stTimeout_t	// 時(shí)間倫
{
	stTimeoutItemLink_t* pItems;	// 時(shí)間輪鏈表,開(kāi)始初始化分配只一圈的長(zhǎng)度,后續(xù)直接使用
	int iItemSize;					// 超時(shí)鏈表中一圈的tick 60*1000
	unsigned long long ullStart;	// 時(shí)間輪開(kāi)始時(shí)間,會(huì)一直變化
	long long llStartIdx;			// 時(shí)間輪開(kāi)始的下標(biāo),會(huì)一直變化
};

// epoll 結(jié)構(gòu)
struct stCoEpoll_t
{
	int iEpollFd;
	static const int _EPOLL_SIZE = 1024 * 10;
	struct stTimeout_t* pTimeout;					// epoll 存著時(shí)間輪
	struct stTimeoutItemLink_t* pstTimeoutList;		// 超時(shí)事件鏈表
	struct stTimeoutItemLink_t* pstActiveList;		// 用于signal時(shí)會(huì)插入
	co_epoll_res* result;
};

也就是說(shuō),一個(gè)協(xié)程,就有一個(gè),在co_init_curr_thread_env 中創(chuàng)建

它管理著超時(shí)鏈表,信號(hào)事件鏈表

其中的pTimeout,就是時(shí)間輪,也就是一個(gè)數(shù)組,這個(gè)數(shù)組的大小位60*1000

圖片

stTimeout_t *AllocTimeout( int iSize )
{
	stTimeout_t *lp = (stTimeout_t*)calloc( 1,sizeof(stTimeout_t) );
	lp- >iItemSize = iSize;
	// 注意這里先把item分配好了,后續(xù)直接使用
	lp- >pItems = (stTimeoutItemLink_t*)calloc( 1, sizeof(stTimeoutItemLink_t) * lp- >iItemSize );
	lp- >ullStart = GetTickMS();
	lp- >llStartIdx = 0;
	return lp;
}

這就是分配的時(shí)間輪的方法,首先指定了下標(biāo)時(shí)間等信息,根據(jù)結(jié)構(gòu)注釋?xiě)?yīng)該不難懂

// apTimeout:時(shí)間輪
// apItem: 某一個(gè)定時(shí)item
// allNow:當(dāng)前的時(shí)間
// 函數(shù)目的,將超時(shí)項(xiàng)apItem加入到apTimeout
int AddTimeout( stTimeout_t *apTimeout, stTimeoutItem_t *apItem ,unsigned long long allNow )
{
// 這個(gè)判斷有點(diǎn)多余,start正常已經(jīng)分配了
if( apTimeout->ullStart == 0 )
{
apTimeout->ullStart = allNow;
apTimeout->llStartIdx = 0;
}
// 當(dāng)前時(shí)間也不大可能比前面的時(shí)間大
if( allNow < apTimeout->ullStart )
{
co_log_err("CO_ERR: AddTimeout line %d allNow %llu apTimeout->ullStart %llu",
LINE ,allNow,apTimeout->ullStart);

return __LINE__;
}
if( apItem- >ullExpireTime < allNow )
{
	co_log_err("CO_ERR: AddTimeout line %d apItem- >ullExpireTime %llu allNow %llu apTimeout- >ullStart %llu",
				__LINE__,apItem- >ullExpireTime,allNow,apTimeout- >ullStart);

	return __LINE__;
}
// 到期時(shí)間到start的時(shí)間差
unsigned long long diff = apItem- >ullExpireTime - apTimeout- >ullStart;
// itemsize 實(shí)際上是毫秒數(shù),如果超出了,說(shuō)明設(shè)置的超時(shí)時(shí)間過(guò)長(zhǎng)
if( diff >= (unsigned long long)apTimeout- >iItemSize )
{
	diff = apTimeout- >iItemSize - 1;
	co_log_err("CO_ERR: AddTimeout line %d diff %d",
				__LINE__,diff);

	//return __LINE__;
}
// 將apItem加到末尾
AddTail( apTimeout- >pItems + ( apTimeout- >llStartIdx + diff ) % apTimeout- >iItemSize , apItem );

return 0;

}

其實(shí),這里有個(gè)概念,stTimeoutItemLink_tstTimeoutItem_t,也就是說(shuō),stTimeout_t里面管理的時(shí)60*1000個(gè)鏈表,而每個(gè)鏈表有一個(gè)或者多個(gè)stTimeoutItem_t,下面這個(gè)函數(shù),就是把節(jié)點(diǎn)Item加入到鏈表的方法。

template
void inline AddTail(TLink*apLink, TNode ap)
{
if( ap->pLink )
{
return ;
}
if(apLink->tail)
{
apLink->tail->pNext = (TNode
)ap;
ap->pNext = NULL;
ap->pPrev = apLink->tail;
apLink->tail = ap;
}
else
{
apLink->head = apLink->tail = ap;
ap->pNext = ap->pPrev = NULL;
}
ap->pLink = apLink;
}

![圖片](//file1.elecfans.com/web2/M00/AD/ED/wKgaomVRwIaAdU0AAADdUXMLTLQ483.jpg)

到這里,基本把一個(gè)超時(shí)事件添加到時(shí)間輪中了,這時(shí)就應(yīng)該切換協(xié)程了co_yield_env

int ret = AddTimeout( ctx->pTimeout, &arg, now );
int iRaiseCnt = 0;
if( ret != 0 )
{
co_log_err("CO_ERR: AddTimeout ret %d now %lld timeout %d arg.ullExpireTime %lld",
ret,now,timeout,arg.ullExpireTime);
errno = EINVAL;
iRaiseCnt = -1;
}
else
{
co_yield_env( co_get_curr_thread_env() );
iRaiseCnt = arg.iRaiseCnt;
}

接下來(lái),看怎么檢測(cè)超時(shí)事件co_eventloop

for(;;)
{
// 等待事件或超時(shí)1ms
int ret = co_epoll_wait( ctx->iEpollFd,result,stCoEpoll_t::_EPOLL_SIZE, 1 );

//  遍歷所有ret事件處理
	for(int i=0;i< ret;i++)
	{
		pfnPrepare(xxx)
	}

	// 取出所有的超時(shí)時(shí)間item,設(shè)置為超時(shí)
	TakeAllTimeout( ctx- >pTimeout, now, plsTimeout );
	stTimeoutItem_t *lp = plsTimeout- >head;
	while( lp )
	{
		lp- >bTimeout = true;
		lp = lp- >pNext;
	}

	// 將超時(shí)鏈表plsTimeout加入到plsActive
	Join< stTimeoutItem_t, stTimeoutItemLink_t >( plsActive, plsTimeout );
	lp = plsActive- >head;
	while( lp )
	{
        // 彈出鏈表頭,處理超時(shí)事件
		PopHead< stTimeoutItem_t,stTimeoutItemLink_t >( plsActive );
        if (lp- >bTimeout && now < lp- >ullExpireTime) 
		{
			int ret = AddTimeout(ctx- >pTimeout, lp, now);
			if (!ret) 
			{
				lp- >bTimeout = false;
				lp = plsActive- >head;
				continue;
			}
		}
        // 只有stPool_t 才需要切協(xié)程,要切回去了
		if( lp- >pfnProcess )
		{
			lp- >pfnProcess( lp );
		}
		lp = plsActive- >head;
	}

	// 如果傳入該函數(shù)指針,則可以控制event_loop 退出
	if( pfn )
	{
		if( -1 == pfn( arg ) )
		{
			break;
		}
	}
}
其中包括了定時(shí)事件處理,協(xié)程切換,主協(xié)程退出等操作。如果設(shè)置了主協(xié)程退出函數(shù),則主協(xié)程可以正常的退出。
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3359

    瀏覽量

    121663
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    41345
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    420

    瀏覽量

    27104
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    390

    瀏覽量

    12031
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    軟件定時(shí)器的特點(diǎn)和原理

    本文介紹了軟件定時(shí)器的特點(diǎn)和原理,并從時(shí)鐘節(jié)拍,數(shù)據(jù)結(jié)構(gòu),定時(shí)器操作等角度分析,實(shí)現(xiàn)了基于STM32的軟件定時(shí)器,該軟件
    發(fā)表于 08-19 08:29

    什么是軟件定時(shí)器?基于STM32的軟件定時(shí)器該怎樣去實(shí)現(xiàn)

    目錄1.什么是軟件定時(shí)器2.軟件定時(shí)器實(shí)現(xiàn)原理3.基于STM32的軟件定時(shí)器3.1 時(shí)鐘節(jié)拍3.2 數(shù)據(jù)結(jié)構(gòu)3.3
    發(fā)表于 12-22 07:47

    GPIB命令的數(shù)據(jù)結(jié)構(gòu)

    針對(duì)GPIB命令的結(jié)構(gòu),提出一種存儲(chǔ)GPIB命令的數(shù)據(jù)結(jié)構(gòu)。根據(jù)GPIB命令的層次關(guān)系的特點(diǎn),選擇數(shù)據(jù)結(jié)構(gòu)中“樹(shù)”的概念來(lái)存儲(chǔ)GPIB命令結(jié)點(diǎn);并考慮程序
    發(fā)表于 02-10 16:20 ?70次下載

    GPIB命令的數(shù)據(jù)結(jié)構(gòu)

    針對(duì)GPIB命令的結(jié)構(gòu),提出一種存儲(chǔ)GPIB命令的數(shù)據(jù)結(jié)構(gòu)。根據(jù)GPIB命令的層次關(guān)系的特點(diǎn),選擇數(shù)據(jù)結(jié)構(gòu)中“樹(shù)”的概念來(lái)存儲(chǔ)GPIB命令結(jié)點(diǎn);并考慮程序
    發(fā)表于 01-04 10:13 ?0次下載

    數(shù)據(jù)結(jié)構(gòu)是什么_數(shù)據(jù)結(jié)構(gòu)有什么用

    數(shù)據(jù)結(jié)構(gòu)是計(jì)算機(jī)存儲(chǔ)、組織數(shù)據(jù)的方式。數(shù)據(jù)結(jié)構(gòu)是指相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。通常情況下,精心選擇
    發(fā)表于 11-17 14:45 ?1.7w次閱讀
    <b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>是什么_<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>有什么用

    降低了CPU負(fù)載率的μC/OS-II定時(shí)器有效改進(jìn)方法

    對(duì)μC/OS-II的定時(shí)器管理算法進(jìn)行改進(jìn)的主要目標(biāo)是:要么不對(duì)定時(shí)器進(jìn)行檢查,要檢查則一定有定時(shí)器到期[2]。為了達(dá)到這個(gè)設(shè)計(jì)目標(biāo),需要對(duì)μC/OS-II的定時(shí)器輪進(jìn)行重新設(shè)計(jì)。采用
    發(fā)表于 07-19 07:06 ?1296次閱讀
    降低了CPU負(fù)載率的μC/OS-II<b class='flag-5'>定時(shí)器</b>有效改進(jìn)方法

    什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)?數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實(shí)例分析

    本文檔的主要內(nèi)容詳細(xì)介紹的是什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實(shí)例分析包括了:數(shù)據(jù)結(jié)構(gòu)在串口通信當(dāng)中的應(yīng)用,數(shù)據(jù)結(jié)構(gòu)在按鍵
    發(fā)表于 09-26 15:45 ?14次下載
    什么是<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?為什么要學(xué)習(xí)<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>的應(yīng)用實(shí)例分析

    STM32基于cubeMX實(shí)現(xiàn)定時(shí)器點(diǎn)燈

    Cortex M3內(nèi)核當(dāng)中的定時(shí)器,它并不屬于芯片廠商的外設(shè),也就是說(shuō)使用ARM內(nèi)核的不同廠商,都擁有基本結(jié)構(gòu)相同的系統(tǒng)定時(shí)器。主要目的是給RTOS提供時(shí)鐘節(jié)拍做時(shí)間基準(zhǔn)?;?b class='flag-5'>定時(shí)器:
    發(fā)表于 11-23 18:21 ?19次下載
    STM32基于cubeMX<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b>點(diǎn)燈

    STM32定時(shí)器-基本定時(shí)器

    目錄定時(shí)器分類基本定時(shí)器功能框圖講解基本定時(shí)器功能時(shí)鐘源計(jì)數(shù)時(shí)鐘計(jì)數(shù)自動(dòng)重裝載寄存
    發(fā)表于 11-23 18:21 ?32次下載
    STM32<b class='flag-5'>定時(shí)器</b>-基本<b class='flag-5'>定時(shí)器</b>

    定時(shí)器作用及實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取介紹1

    定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行定時(shí)
    的頭像 發(fā)表于 04-21 15:20 ?1833次閱讀
    <b class='flag-5'>定時(shí)器</b>作用及<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b><b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>選取介紹1

    定時(shí)器作用及實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取介紹2

    定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行定時(shí)
    的頭像 發(fā)表于 04-21 15:20 ?1736次閱讀
    <b class='flag-5'>定時(shí)器</b>作用及<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b><b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>選取介紹2

    什么是軟件定時(shí)器?軟件定時(shí)器實(shí)現(xiàn)原理

    軟件定時(shí)器是用程序模擬出來(lái)的定時(shí)器,可以由一個(gè)硬件定時(shí)器模擬出成千上萬(wàn)個(gè)軟件定時(shí)器,這樣程序在需要使用較多定時(shí)器的時(shí)候就不會(huì)受限于硬件資源的
    的頭像 發(fā)表于 05-23 17:05 ?3993次閱讀

    STM32如何使用定時(shí)器實(shí)現(xiàn)微秒(us)級(jí)延時(shí)?

    如何使用定時(shí)器實(shí)現(xiàn)微秒級(jí)延時(shí)的步驟: 步驟 1:配置定時(shí)器 首先,需要選擇一個(gè)適合的定時(shí)器。大多數(shù)STM32微控制
    的頭像 發(fā)表于 11-06 11:05 ?8593次閱讀

    定時(shí)器設(shè)計(jì)實(shí)現(xiàn)

    返回ITimer類型的共享指針。其中ITimer類中定義了start和stop方法,用于啟動(dòng)或停止當(dāng)前定時(shí)器。 TimerManager還有一個(gè)內(nèi)部類TimerMessageQueue用于實(shí)現(xiàn)
    的頭像 發(fā)表于 11-08 16:50 ?1293次閱讀

    redis數(shù)據(jù)結(jié)構(gòu)的底層實(shí)現(xiàn)

    Redis是一種內(nèi)存鍵值數(shù)據(jù)庫(kù),常用于緩存、消息隊(duì)列、實(shí)時(shí)數(shù)據(jù)分析等場(chǎng)景。它的高性能得益于其精心設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu)和底層實(shí)現(xiàn)。本文將詳細(xì)介紹Redis常用的
    的頭像 發(fā)表于 12-05 10:14 ?1094次閱讀