Linux epoll 筆記(高并發事件處理機制)

wiki

Epoll優點;

Epoll工作流程;

Epoll實現機制:

  epollevent;

Epoll源碼分析;

Epoll接口:

  epoll_create;

  epoll_ctl;

  epoll_close;

Epoll工作方式:

  LT(level-triggered);

  ET(edge-triggered);

Epoll應用模式;

?

Epoll優點:

<1>支持一個進程打開大數目的socket描述符(FD)

?select一個進程所打開的FD是有一定限制的,由FD_SETSIZE設置,默認值是2048。可以選擇修改這個宏然后重新編譯內核,不過資料也同時指出這樣會帶來網絡效率的下降,二是可以選擇多進程的解決方案(傳統的 Apache方案),不過雖然linux上面創建進程的代價比較小,但仍舊是不可忽視的,加上進程間數據同步遠比不上線程間同步的高效,所以也不是一種完美的方案。不過 epoll則沒有這個限制,它所支持的FD上限是最大可以打開文件的數目,這個數字一般遠大于2048,舉個例子,在1GB內存的機器上大約是10萬左 右,具體數目可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統內存關系很大。

?<2>IO效率不隨FD數目增加而線性下降

epoll只會對"活躍"的socket進行操 作---這是因為在內核實現中epoll是根據每個fd上面的callback函數實現的。那么,只有"活躍"的socket才會主動的去調用 callback函數,其他idle狀態socket則不會,在這點上,epoll實現了一個"偽"AIO,因為這時候推動力在os內核。在一些 benchmark中,如果所有的socket基本上都是活躍的---比如一個高速LAN環境,epoll并不比select/poll有什么效率,相反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模擬WAN環境,epoll的效率就遠在select/poll之上了。同時對于監聽的fd很多,但是活躍的fd很少的情況下epoll相比select也有很高的效率。

?<3>使用mmap加速內核與用戶空間的消息傳遞。

無論是select,poll還是epoll都需要內核把FD消息通知給用戶空間,如何避免不必要的內存拷貝就很重要,在這點上,epoll是通過內核于用戶空間mmap同一塊內存實現的。

?<4>內核微調

這一點其實不算 epoll 的優點了,而是整個linux平臺的優點。也許你可以懷疑linux平臺,但是你無法回避linux平臺賦予你微調內核的能力。比如,內核TCP/IP協 議棧使用內存池管理sk_buff結構,那么可以在運行期動態調整這個內存pool(skb_head_pool)的大小--- 通過echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函數的第2個參數(TCP完成3次握手 的數據包隊列長度),也可以根據你平臺內存大小動態調整。更甚至在一個數據包面數目巨大但同時每個數據包本身大小卻很小的特殊系統上嘗試最新的NAPI網 卡驅動架構。

?<5>與select相比,不復用監聽的文件描述集合來傳遞結果

這樣不需要每次等待前對文件描述符集合重新賦值。

?

Epoll工作流程:

Epoll實現機制:

epoll fd有一個私有的struct eventpoll,它記錄哪一個fd注冊到了epfd上。eventpoll 同樣有一個等待隊列,記錄所有等待的線程。還有一個預備好的fd列表,這些fd可以進行讀或寫。相關內核實現代碼fs/eventpoll.c,判斷是否tcp有激活事件嗎:net/ipv4/tcp.c:tcp_poll函數;????

struct eventpoll {

??? /* Protect the access to this structure */

??? spinlock_t lock;

?

??? /*

??? * This mutex is used to ensure that files are not removed

??? * while epoll is using them. This is held during the event

??? * collection loop, the file cleanup path, the epoll file exit

??? * code and the ctl operations.

??? */

??? struct mutex mtx;

?

??? /* Wait queue used by sys_epoll_wait() */

??? wait_queue_head_t wq;

?

??? /* Wait queue used by file->poll() */

??? wait_queue_head_t poll_wait;

?

??? /* List of ready file descriptors */

??? struct list_head rdllist;//調用epoll_wait的時候,readylist中的epitem出列,將觸發的事件拷貝到用戶空間.之后判斷epitem是否需要重新添加回readylist.

?

??? /* RB tree root used to store monitored fd structs */

??? struct rb_root rbr;//紅黑樹的根,一個fd被添加到epoll中之后(EPOLL_ADD),內核會為它生成一個對應的epitem結構對象.epitem被添加到rbr中。該結構保存了epoll監視的文件描述符。

?

??? /*

??? * This is a single linked list that chains all the "struct epitem" that

??? * happened while transferring ready events to userspace w/out

??? * holding ->lock.

??? */

??? struct epitem *ovflist;

?

??? /* The user that created the eventpoll descriptor */

??? struct user_struct *user;

};

?

?

epitem重新添加到readylist必須滿足下列條件:

1) epitem上有用戶關注的事件觸發.

2) epitem被設置為水平觸發模式(如果一個epitem被設置為邊界觸發則這個epitem不會被重新添加到readylist

?

注意,如果epitem被設置為EPOLLONESHOT模式,則當這個epitem上的事件拷貝到用戶空間之后,會將

這個epitem上的關注事件清空(只是關注事件被清空,并沒有從epoll中刪除,要刪除必須對那個描述符調用

EPOLL_DEL),也就是說即使這個epitem上有觸發事件,但是因為沒有用戶關注的事件所以不會被重新添加到

readylist.

?

epitem被添加到readylist中的各種情況(當一個epitem被添加到readylist如果有線程阻塞在epoll_wait,

個線程會被喚醒):

1)對一個fd調用EPOLL_ADD,如果這個fd上有用戶關注的激活事件,則這個fd會被添加到readylist.

?2)對一個fd調用EPOLL_MOD改變關注的事件,如果新增加了一個關注事件且對應的fd上有相應的事件激活,

則這個fd會被添加到readylist.

?3)當一個fd上有事件觸發時(例如一個socket上有外來的數據)會調用ep_poll_callback(eventpoll::ep_ptable_queue_proc),

如果觸發的事件是用戶關注的事件,則這個fd會被添加到readylist.

?

了解了epoll的執行過程之后,可以回答一個在使用邊界觸發時常見的疑問.在一個fd被設置為邊界觸發的情況下,

調用read/write,如何正確的判斷那個fd已經沒有數據可讀/不再可寫.epoll文檔中的建議是直到觸發EAGAIN

錯誤.而實際上只要你請求字節數小于read/write的返回值就可以確定那個fd上已經沒有數據可讀/不再可寫.

最后用一個epollfd監聽另一個epollfd也是合法的,epoll通過調用eventpoll::ep_eventpoll_poll來判斷一個

epollfd上是否有觸發的事件(只能是讀事件).

?

Epoll源碼分析:

涉及linux模塊的編寫;

<<Epoll源碼分析.doc>>

Epoll module:

static int __init eventpoll_init(void){

//模塊初始化函數

}

eventpoll_init函數源碼

static int __init eventpoll_init(void)

{

int error;

?

init_MUTEX(&epsem);

?

/* Initialize the structure used to perform safe poll wait head wake ups */

ep_poll_safewake_init(&psw);

?

/* Allocates slab cache used to allocate "struct epitem" items */

epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),

0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,

NULL, NULL);

?

/* Allocates slab cache used to allocate "struct eppoll_entry" */

pwq_cache = kmem_cache_create("eventpoll_pwq",

sizeof(struct eppoll_entry), 0,

EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);

?

/*

?* Register the virtual file system that will be the source of inodes

?

?* for the eventpoll files

?*/

/*注冊了一個新的文件系統,叫"eventpollfs"(在eventpoll_fs_type結構里),然后掛載此文件系統*/

error = register_filesystem(&eventpoll_fs_type);

if (error)

goto epanic;

?

/* Mount the above commented virtual file system */

eventpoll_mnt = kern_mount(&eventpoll_fs_type);

error = PTR_ERR(eventpoll_mnt);

if (IS_ERR(eventpoll_mnt))

goto epanic;

?

DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n",

current));

return 0;

?

epanic:

panic("eventpoll_init() failed\n");

}

epoll是個module,所以先看看module的入口eventpoll_init。這個module在初始化時注冊了一個新的文件系統,叫"eventpollfs"(在eventpoll_fs_type結構里),然后掛載此文件系統。另外創建兩個內核cache(在內核編程中,如果需要頻繁分配小塊內存,應該創建kmem_cahe來做“內存池”),分別用于存放struct epitemeppoll_entry

?

?

Epoll的接口:

epollLinux內核為處理大批句柄而作改進的pollLinux下多路復用IO接口select/poll的增強版本,它能顯著的減少程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率。因為它會復用文件描述符集合來傳遞結果而不是迫使開發者每次等待事件之前都必須重新準備要被偵聽的文件描述符集合,另一個原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select\poll那種IO事件的電平觸發(Level Triggered)外,還提供了邊沿觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提供應用程序的效率。

1.工作函數

1>.int epoll_create(int size);

創建一個epoll的句柄,size用來告訴內核這個監聽的數目fd+1,每個epoll都會占用一個fd值,可以在/proc/進程id/fd/查看。記得close()

2>.int epoll_ctl(int epfd,int op,int fd ,struct epoll_event *event);

epoll的事件注冊函數,epoll的控制函數;

這里先注冊要監聽的事件類型。第一個參數是epoll_create()的返回值,第二個參數表示動作,用三個宏來表示:

EPOLL_CTL_ADD:注冊新的fdepfd中;

EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;

EPOLL_CTL_DEL:從epfd中刪除一個fd

第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什么事,struct epoll_event結構如下:

?

typedef union epoll_data {

??? void *ptr;//數據指針

??? int fd;/*descriptor*/

??? __uint32_t u32;

??? __uint64_t u64;

} epoll_data_t;

?

struct epoll_event {

??? __uint32_t events; /* Epoll events type */

??? epoll_data_t data; /* User data variable */

};

?

epoll_event->data涵蓋了調用epoll_ctl增加或者修改某指定句柄時寫入的信息,epoll_event->event,則包含了返回事件的位域。

?

events可以是以下幾個宏的集合:

EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);

EPOLLOUT:表示對應的文件描述符可以寫;

EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);

EPOLLERR:表示對應的文件描述符發生錯誤;

EPOLLHUP:表示對應的文件描述符被掛斷;

EPOLLET EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對于水平觸發(Level Triggered)來說的。

EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里

?

enum EPOLL_EVENTS

? {

??? EPOLLIN = 0x001,

#define EPOLLIN EPOLLIN

??? EPOLLPRI = 0x002,

#define EPOLLPRI EPOLLPRI

??? EPOLLOUT = 0x004,

#define EPOLLOUT EPOLLOUT

??? EPOLLRDNORM = 0x040,

#define EPOLLRDNORM EPOLLRDNORM

??? EPOLLRDBAND = 0x080,

#define EPOLLRDBAND EPOLLRDBAND

??? EPOLLWRNORM = 0x100,

#define EPOLLWRNORM EPOLLWRNORM

??? EPOLLWRBAND = 0x200,

#define EPOLLWRBAND EPOLLWRBAND

??? EPOLLMSG = 0x400,

#define EPOLLMSG EPOLLMSG

??? EPOLLERR = 0x008,

#define EPOLLERR EPOLLERR

??? EPOLLHUP = 0x010,

#define EPOLLHUP EPOLLHUP

??? EPOLLRDHUP = 0x2000,

#define EPOLLRDHUP EPOLLRDHUP

??? EPOLLWAKEUP = 1u << 29,

#define EPOLLWAKEUP EPOLLWAKEUP

??? EPOLLONESHOT = 1u << 30,

#define EPOLLONESHOT EPOLLONESHOT

??? EPOLLET = 1u << 31

#define EPOLLET EPOLLET

? };

?

3>. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

等待事件的產生,類似于select()調用。參數events用來從內核得到事件的集合maxevents告之內核這個events有多大,這個 maxevents的值不能大于創建epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函數返回需要處理的事件數目,如返回0表示已超時。

?

工作方式:

LT/ET:

LT(level triggered):水平觸發,缺省方式,同時支持blockno-block socket,在這種做法中,內核告訴我們一個文件描述符是否被就緒了,如果就緒了,你就可以對這個就緒的fd進行IO操作。如果你不作任何操作,內核還是會繼續通知你的,所以,這種模式編程出錯的可能性較小。傳統的select\poll都是這種模型的代表。

?

ET(edge-triggered):邊沿觸發,高速工作方式,只支持no-block socket。在這種模式下,當描述符從未就緒變為就緒狀態時,內核通過epoll告訴你。然后它會假設你知道文件描述符已經就緒,并且不會再為那個描述符發送更多的就緒通知,直到你做了某些操作導致那個文件描述符不再為就緒狀態了(比如:你在發送、接受或者接受請求,或者發送接受的數據少于一定量時導致了一個EWOULDBLOCK錯誤)。但是請注意,如果一直不對這個fs做IO操作(從而導致它再次變成未就緒狀態),內核不會發送更多的通知。

?

應用模式:

那么究竟如何來使用epoll呢?其實非常簡單。

通過在包含一個頭文件#include <sys/epoll.h> 以及幾個簡單的API將可以大大的提高你的網絡服務器的支持人數。

?

首先通過create_epoll(int maxfds)來創建一個epoll的句柄,其中maxfds為你epoll所支持的最大句柄數。這個函數會返回一個新的epoll句柄,之后的所有操作將通過這個句柄來進行操作。在用完之后,記得用close()來關閉這個創建出來的epoll句柄。

?

之后在你的網絡主循環里面,每一幀的調用epoll_wait(int epfd, epoll_event events, int max events, int timeout)來查詢所有的網絡接口,看哪一個可以讀,哪一個可以寫了。基本的語法為:

nfds = epoll_wait(kdpfd, events, maxevents, -1);

其中kdpfd為用epoll_create創建之后的句柄,events是一個epoll_event*的指針,當epoll_wait這個函數操作成功之后,epoll_events里面將儲存所有的讀寫事件。max_events是當前需要監聽的所有socket句柄數。最后一個timeout epoll_wait的超時,為0的時候表示馬上返回,為-1的時候表示一直等下去,直到有事件范圍,為任意正整數的時候表示等這么長的時間,如果一直沒有事件,則范圍。一般如果網絡主循環是單獨的線程的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個線程的話,則可以用0來保證主循環的效率。

?

epoll_wait范圍之后應該是一個循環,遍利所有的事件。

?

幾乎所有的epoll程序都使用下面的框架(尤其是socket)

?

??? for( ; ; )

??? {

??????? nfds = epoll_wait(epfd,events,20,500);

??????? for(i=0;i<nfds;++i)

??????? {

??????????? if(events[i].data.fd==listenfd) //有新的連接;我們可以注冊多個FD,如果內核發現事件,就會載入events,如果有我們要的描述符也就是listenfd,說明某某套接字監聽描述符所對應的事件發生了變化。每次最多監測20fd數。

??????????? {

??????????????? connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); //accept這個連接

??????????????? ev.data.fd=connfd;

??????????????? ev.events=EPOLLIN|EPOLLET;//LT

??????????????? epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); //將新的fd添加到epoll的監聽隊列中

??????????? }

??????????? else if( events[i].events&EPOLLIN ) //接收到數據,讀socket,數據可讀標志EPOLLIN

??????????? {

??????????????? n = read(sockfd, line, MAXLINE)) < 0??? //讀

??????????????? ev.data.ptr = md;???? //md為自定義類型,添加數據

??????????????? ev.events=EPOLLOUT|EPOLLET;

??????????????? epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);//修改標識符,等待下一個循環時發送數據,異步處理的精髓

??????????? }

??????????? else if(events[i].events&EPOLLOUT) //有數據待發送,寫socket

??????????? {

??????????????? struct myepoll_data* md = (myepoll_data*)events[i].data.ptr;??? //取數據

??????????????? sockfd = md->fd;

??????????????? send( sockfd, md->ptr, strlen((char*)md->ptr), 0 );??????? //發送數據

??????????????? ev.data.fd=sockfd;

??????????????? ev.events=EPOLLIN|EPOLLET;

??????????????? epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); //修改標識符,等待下一個循環時接收數據

??????????? }

??????????? else

??????????? {

??????????????? //其他的處理

??????????? }

??????? }

??? }

1.Linux下多線程epoll編程

來自 <http://blog.csdn.net/susubuhui/article/details/37906287>

2.epoll + 多線程實現并發網絡連接處理

來自 <http://www.cnblogs.com/iTsihang/archive/2013/05/23/3095775.html>

3.高并發的epoll+線程池,業務在線程池內

來自 <http://blog.chinaunix.net/uid-311680-id-2439722.html>?

轉載于:https://www.cnblogs.com/ypwen/p/4725532.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/459040.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/459040.shtml
英文地址,請注明出處:http://en.pswp.cn/news/459040.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Django請求響應對象

請求與響應對象 HttpRequest HttpRequest存儲了客戶請求的相關參數和一些查詢方法。 path請求頁面的全路徑,不包括域名—例如, "/hello/"。 methodHttp請求方法&#xff0c;包括GET,POST。 GETQueryDict類實例&#xff0c;包含所有HTTP GET參數的字典對象。 POSTQuer…

matlab 作圖 虛線太長,matlab?極坐標繪圖?在matlab中,用polar畫的圖形,如何使虛線圓多顯示幾個?...

滿意答案iredwood推薦于 2018.12.26采納率&#xff1a;52% 等級&#xff1a;12已幫助&#xff1a;13535人打開polar.m 文件&#xff0c;路徑可通過輸入 which polar 命令得到。其中修改下面這段代碼&#xff0c;可以控制虛線圓的顯示個數。其中rticks 為控制顯示個數的參量。…

《學習opencv》筆記——矩陣和圖像處理——cvAnd、cvAndS、cvAvg and cvAvgSdv

矩陣和圖像的操作 (1)cvAnd函數 其結構 void cvAnd( //將src1和src2按像素點取“位與運算”const CvArr* src1,//第一個矩陣const CvArr* src2,//第二個矩陣CvArr* dst,//結果矩陣const CvArr* mask NULL;//矩陣經行像素點與的“開關” );程序實例#include <cv.h> #inc…

Hibernate之加載策略(延遲加載與即時加載)和抓取策略(fetch)

假設現在有Book和Category兩張表,表的關系為雙向的一對多,表結構如下: 假設現在我想查詢id為2的那本書的書名,使用session.get(...)方法: 1 Session sessionHibernateUtil.getSession(); 2 Book book (Book) session.get(Book.class,2); 3 System.out.println(book.getName());…

指紋圖像方向圖matlab,matlab指紋方向場方向圖程序

function Fangxiangtu zhiwen_fangxiangtu( Zhiwentuxiang )%函數功能計算指紋方向圖%函數參數指紋圖像Zhiwentuxiang%函數返回值指紋方向圖FangxiangtuSizeZhiwentuxiang size( Zhiwentuxiang ) ;Zhiwentuxiang double( Zhiwentuxiang ) ;W 4; % 窗口大小(2W1)*(2W1)W 4;…

怎樣實現一個簡單的jQuery編程

第一步&#xff1a;在head中載入jQuery框架 <script  type"text/javascript" src"jQuery文檔所在的絕對路徑"></script> 注&#xff1a; type——指定腳本的mime類型 src——規定外部腳本文件的URL jQuery是一個javascript庫&#xff0c;相…

php多人點餐可以看到對方點的菜,千萬不要小看你身邊那個會點菜的人,因為

飯局上&#xff0c;你常常是負責點菜的那個人&#xff0c;還是只負責吃&#xff1f;拿起菜單點菜&#xff0c;你是很從容&#xff0c;還是不知道怎么點&#xff1f;事實上&#xff0c;飯局上那個會點菜的人&#xff0c;千萬不能小看。某次隨老板外出開會&#xff0c;跟去的幾個…

gvim for php,轉 : Gvim建立IDE編程環境 (Windows篇)

說明&#xff1a;本文是作者在完全按照著名的《手把手教你把Vim改裝成一個IDE編程環境》一文&#xff0c;在Windows XP上用gvim建立IDE環境時所作的備忘。原作地址&#xff1a;http://blog.csdn.net/wooin/archive/2007/10/31/1858917.aspx。1.安裝gvim7.2。運行gvim72.exe&…

1081. Rational Sum (20) -最大公約數

題目如下&#xff1a; Given N rational numbers in the form "numerator/denominator", you are supposed to calculate their sum. Input Specification: Each input file contains one test case. Each case starts with a positive integer N (<100), followe…

CRC8校驗分析

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** CRC即循環冗余校驗碼&#xff08;Cyclic Redundancy Check&#xff09;&#xff1a;是…

insert mysql后加where,如何在MySQL Insert語句中添加where子句?

This doesnt work:這不起作用:INSERT INTO users (username, password) VALUES ("Jack","123") WHERE id1;Any ideas how to narrow insertion to a particular row by id?任何想法如何通過id縮小插入到特定行?8 個解決方案#120In an insert statement y…

阿里云使用筆記-Lrzsz上傳下載文件-centos7

2019獨角獸企業重金招聘Python工程師標準>>> 上傳文件時提示&#xff1a; -bash: rz: command not found rz命令沒找到&#xff1f; 執行sz&#xff0c;同樣也沒找到。 原來是要安裝個叫 lrzsz 的東西&#xff0c;一查可以直接yum。 安裝lrzsz&#xff1a;# yum -y …

C#中的DBNull、Null、String.Empty和“”

null可賦值任何變量,將變量置為空 DBNull只用于DataRow對象,表示數據庫中的空值 String.Empty是0長度字串 Convert.IsDBNull判斷是否為DBNull DBNull.Value與Null的區別 Null是.net中無效的對象引用。 DBNull是一個類。DBNull.Value是它唯一的實例。它指數據庫中數據為空(&l…

matlab數值很小出錯,求大神幫忙解決一下,用MATLAB求解動力學數據總是出錯~ - 計算模擬 - 小木蟲 - 學術 科研 互動社區...

CODE:function KineticsEst5 % 動力學ODE方程模型的參數估計%%%% The variables y here are y(1)xB, y(2)xoNB, y(3)xmNB,y(4)xpNB,y(5)xDNB .clear allclck0 [5 5 5 5 5]; % 參數初值lb [0 0 0 0 0]; % 參數下限ub [inf inf inf inf inf]; % 參數上限x0 [0 0 0 0 0 0];Kin…

iOS開發--驗證碼

第一步&#xff0c;拖兩個空間textfiled和button到storyboard上的viewcontroller上。 第二步&#xff0c;拖線&#xff0c;鏈接到.h文件中代碼如下&#xff1a; 1property (weak, nonatomic) IBOutlet UIButton *l_timeButton;第三步&#xff0c;在,m文件中為l_timeButton設置監…

Standard C Episode 8

C語言函數和程序結構 通過函數可以把大的計算任務分解成若干個較小任務&#xff0c;從而使得思路更加清晰&#xff0c;同時函數也大大提高了代碼的復用率&#xff0c;提高了工作效率。要注意的是多函數之間應該盡可能地高聚合低耦合。另一方面&#xff0c;一個程序可以保存在一…

C# Socket 編程詳解

Microsoft.Net Framework為應用程序訪問Internet提供了分層的、可擴展的以及受管轄的網絡服務&#xff0c;其名字空間System.Net和 System.Net.Sockets包含豐富的類可以開發多種網絡應用程序。.Net類采用的分層結構允許應用程序在不同的控制級別上訪問網絡&#xff0c;開發人員…

java 線程池 wait,Java 多線程 之 wait等待 線程實例

package com.wait.notify;/**題目: 人們在火車站的售票窗口排隊買火車票1. 北京西站開門2. 打開售票窗口3. 北京西站有10張去長沙的票4. 打開2個售票窗口,5 假設每個售票窗口每隔1秒鐘買完一張票1. 根據 名詞 找類人們(Person), 火車站(Station),火車票(Ticket) , 售票窗口e 是…

002 exercises

求列表全排列lst [1,2,3] l1 [(x,y,z) for x in lst for y in lst for z in lst if x ! y if y ! z if x ! z] print(l1)給定一個非負整數num,重復的加每一位,直到最后只剩下一位例如: num 38,計算過程如下:3 8 111 1 2最后輸出結果為2#遞歸 def add(num):if len(str(num…

(線段樹 點更新 區間求和)lightoj1112

鏈接&#xff1a; http://acm.hust.edu.cn/vjudge/contest/view.action?cid88230#problem/D &#xff08;密碼0817&#xff09; Description Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money togeth…