真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Linux網(wǎng)絡設計之協(xié)程原理-創(chuàng)新互聯(lián)

協(xié)程原理
  • 一、協(xié)程的意義
  • 二、異步的執(zhí)行流程
  • 三、協(xié)程的基本操作
    • 3.1、“切換”的方式--switch
    • 3.2、create:創(chuàng)建協(xié)程
    • 3.3、yield:讓出CPU
    • 3.4、resume:恢復協(xié)程運行權
  • 四、協(xié)程的定義
  • 五、調度器的定義
  • 總結
  • 后言

創(chuàng)新互聯(lián)專注于企業(yè)成都營銷網(wǎng)站建設、網(wǎng)站重做改版、陵川網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、H5高端網(wǎng)站建設、商城系統(tǒng)網(wǎng)站開發(fā)、集團公司官網(wǎng)建設、外貿(mào)網(wǎng)站建設、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為陵川等各大城市提供網(wǎng)站開發(fā)制作服務。一、協(xié)程的意義

協(xié)程可以看作一個輕量級的線程,能自己實現(xiàn)調度。有一些輕量的場景,如網(wǎng)絡刷新、網(wǎng)絡加載、UI刷新、IO讀寫操作等,可以不需要開啟一個線程去執(zhí)行;線程或進程的調度較重,只需要一個輕量級的線程來維護業(yè)務代碼,使業(yè)務代碼更加的輕便靈活;這就是協(xié)程的意義。協(xié)程,簡單的說,就是一個具有異步的性能,卻使用同步編程方式的組件。使用者調用協(xié)程可以很好的管理業(yè)務代碼,整個執(zhí)行過程清晰明了。

二、異步的執(zhí)行流程

多線程異步操作,就是將不同的操作放到不同的線程中進行。異步帶來的好處是子模塊好規(guī)劃、程序性能高;缺點是模塊間的數(shù)據(jù)管理異常麻煩。

多線程異步簡單示例代碼:

#include#include#include#include#include#include#include#include#include#include#include#include#include#define ASYNC_EVENT_LENGTH 1024

struct context {int epfd;
	pthread_t thid;
};

void *asyn_callback(void * arg)
{struct context *ctx=(struct context*)arg;
	while(1)
	{struct epoll_event events[ASYNC_EVENT_LENGTH] = {0 };
		int nready=epoll_wait(ctx->epfd,events,ASYNC_EVENT_LENGTH,-1);
		if (nready< 0)
		{	if (errno == EINTR || errno == EAGAIN)
				continue;
			else
				break;
		}
		else if (nready == 0)
			continue;

		int i = 0;
		for (i = 0; i< nready;i++)
		{	int clientfd = events[i].data.fd;
			if (events[i].events &EPOLLIN)
			{		char buffer[1024] = {0 };
				struct sockaddr_in addr;
				size_t addr_len = sizeof(struct sockaddr_in);

				// 從讀緩沖區(qū)中讀取數(shù)據(jù)
				int n = recvfrom(clientfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);

				printf("recvfrom n : %d\n", n);

				// 解析數(shù)據(jù)
				parse_response(buffer);

				// 刪除事件監(jiān)聽
				epoll_ctl(ctx->epfd, EPOLL_CTL_DEL, clientfd, NULL);

				// 關閉fd
				close(clientfd);
			}
		}
	}
	return NULL;
}

int asyn_commit(struct context *ctx)
{// 創(chuàng)建 socket
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd< 0) {perror("create socket failed\n");
		exit(-1);
	}
	// 配置socket相關信息
	struct sockaddr_in dest;
	bzero(&dest, sizeof(dest));
	dest.sin_family = AF_INET;
	dest.sin_port = htons(53);
	dest.sin_addr.s_addr = inet_addr(DNS_SVR);

	// connect目標,探路
	int ret = connect(sockfd, (struct sockaddr*)&dest, sizeof(dest));
	printf("connect :%d\n", ret);

	// 準備協(xié)議
	//......
	
	// 發(fā)送數(shù)據(jù)
	int slen = sendto(sockfd, request, req_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr));

	// 加入epoll中,監(jiān)測結果返回
	struct epoll_event ev;
	ev.events = EPOLLIN;
	ev.data.fd = sockfd;

	return epoll_ctl(ctx->epfd, EPOLL_CTL_ADD, sockfd, &ev);

}

int asyn_init(struct context *ctx)
{ctx->epfd=epoll_create(1);
	pthread_create(&ctx->thid,NULL,asyn_callback,ctx);
}


int main(int argc;char *argv[])
{struct context ctx;
	asyn_init(&ctx);
	for(int i=0;i<100;i++)
	{	asyn_commit();
	}
	
	getchar();
	return 0;
}

協(xié)程就是要在一個線程中實現(xiàn)異步操作。

三、協(xié)程的基本操作

協(xié)程主要有幾個操作:創(chuàng)建(create)、讓出(yield)和恢復(resume)。這后兩個操作使用一個關鍵的動作,switch,即切換。
(1)將socketfd添加到epoll中管理。
(2)然后切換上下文,由協(xié)程上下文切換到調度器上下文,這個過程稱為讓出(yield)。
(3)調度器獲取下一個協(xié)程上下文,恢復(resume)新的協(xié)程。
如此達到異步的操作。
調度器與協(xié)程的上下文切換如下圖:

epoll_ctl() add和del動作能夠保證 sockfd 只在一個上下文中能夠操作 IO ;不會出現(xiàn)在多個上下文同時對一個 IO 進行操作。
IO異步操作上下文切換時序圖:

3.1、“切換”的方式–switch

執(zhí)行切換有三種方式:
(1)longjmp / setjmp
(2)ucontext
(3)匯編
”切換“不能使用goto。goto只能在棧內(nèi)跳轉,只能在函數(shù)內(nèi),不能跨函數(shù)。

匯編實現(xiàn)switch可以參考Linux kernel的任務調度方式,在“切換”前保存當前的上下文信息再加載要執(zhí)行的上下文信息。x86_64 的寄存器有 16 個 64 位寄存器:rax,rbx,rdi,rsi,rdx,rcx,r8,r9,r10,r11,r12,r13,r14,r15,rbp,rsp。
其中:
rax:存儲函數(shù)的返回值;
rdi,rsi,rdx,rcx,r8,r9:函數(shù)的六個參數(shù),如果函數(shù)的參數(shù)超過六個,那么六個以后的參數(shù)會入棧。
rbp:棧指針寄存器,指向棧底;
rsp:棧指針寄存器,指向棧頂。
其余的用作數(shù)據(jù)存儲。
eip:指令指針寄存器,指向CPU要執(zhí)行的下一個指令。
例如,對于X86-64的匯編切換代碼:

__asm__ (
"    .text                                  \n"
"       .p2align 4,,15                                   \n"
".globl _switch                                          \n"
".globl __switch                                         \n"
"_switch:                                                \n"
"__switch:                                               \n"
"       movq %rsp, 0(%rsi)      # save stack_pointer     \n"
"       movq %rbp, 8(%rsi)      # save frame_pointer     \n"
"       movq (%rsp), %rax       # save insn_pointer      \n"
"       movq %rax, 16(%rsi)                              \n"
"       movq %rbx, 24(%rsi)     # save rbx,r12-r15       \n"
"       movq %r12, 32(%rsi)                              \n"
"       movq %r13, 40(%rsi)                              \n"
"       movq %r14, 48(%rsi)                              \n"
"       movq %r15, 56(%rsi)                              \n"
"       movq 56(%rdi), %r15                              \n"
"       movq 48(%rdi), %r14                              \n"
"       movq 40(%rdi), %r13     # restore rbx,r12-r15    \n"
"       movq 32(%rdi), %r12                              \n"
"       movq 24(%rdi), %rbx                              \n"
"       movq 8(%rdi), %rbp      # restore frame_pointer  \n"
"       movq 0(%rdi), %rsp      # restore stack_pointer  \n"
"       movq 16(%rdi), %rax     # restore insn_pointer   \n"
"       movq %rax, (%rsp)                                \n"
"       ret                                              \n"
);
3.2、create:創(chuàng)建協(xié)程

(1)如果調度器不存在,則創(chuàng)建調度器。調度器作為全局實例。
(2)分配協(xié)程內(nèi)存空間,并設置協(xié)程的數(shù)據(jù)項。如協(xié)程的??臻g、棧大小、子過程回調函數(shù)、子過程回調參數(shù)等等。
(3)將新創(chuàng)建的協(xié)程添加到就緒隊列中。

3.3、yield:讓出CPU

切換到最近執(zhí)行 resume 的上下文。

3.4、resume:恢復協(xié)程運行權

切換到運行協(xié)程實例的 yield 的位置。
resume 與 yield 是兩個可逆過程的原子操作。

四、協(xié)程的定義

協(xié)程一般包含幾個內(nèi)容:
(1)協(xié)程ID
(2)協(xié)程上下文
(3)協(xié)程入口函數(shù)
(4)協(xié)程的狀態(tài)
(5)協(xié)程的??臻g
(6)返回值
(7)狀態(tài)集合

struct coroutine{uint64_t birth;//創(chuàng)建時間
	uint64_t id;//協(xié)程ID
	
	struct context ctx;//上下文
	
	void *(*func) (void*);//子過程回調函數(shù)
	void *arg;//回調函數(shù)參數(shù)
	
	struct nty_coroutine_status status;// 協(xié)程的狀態(tài)
	
	void *stack;// 棧
	size_t stack_length;//棧大小
	
	nty_schedule *sched;//調度器
	
	//狀態(tài)集合
	struct rbtree_node wait;
	struct queue_node ready;
	struct rbtree_node sleep;
}
五、調度器的定義
typedef struct _nty_coroutine_queue nty_coroutine_queue;
typedef struct _nty_coroutine_rbtree_sleep nty_coroutine_rbtree_sleep;
typedef struct _nty_coroutine_rbtree_wait nty_coroutine_rbtree_wait;

typedef struct _nty_schedule {uint64_t birth;//創(chuàng)建時間
	nty_cpu_ctx ctx;//上下文
	
	struct _nty_coroutine *curr_thread;//當前運行的協(xié)程
	
	int page_size;
	
	// epoll 管理
	int poller_fd;
	int eventfd;
	struct epoll_event eventlist[NTY_CO_MAX_EVENTS];
	int nevents;
	int num_new_events;
	
	//狀態(tài)集合
	nty_coroutine_queue ready;
	nty_coroutine_rbtree_sleep sleeping;
	nty_coroutine_rbtree_wait waiting;
} nty_schedule;
總結

協(xié)程可以讓業(yè)務代碼易于管理,整個流程清晰;自己實現(xiàn)調度器,在單線程中實現(xiàn)異步調度。協(xié)程的底層還是使用epoll等IO多路復用器,性能上只能趨近reactor。
協(xié)程的單核運行過程:

后言

本專欄知識點是通過<零聲教育>的系統(tǒng)學習,進行梳理總結寫下文章,對c/c++linux系統(tǒng)提升感興趣的讀者,可以點擊鏈接,詳細查看詳細的服務:C/C++服務器課程

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧


文章標題:Linux網(wǎng)絡設計之協(xié)程原理-創(chuàng)新互聯(lián)
網(wǎng)頁網(wǎng)址:http://weahome.cn/article/ccsehs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部