select,poll,epoll都是IO多路復(fù)用的機(jī)制。I/O多路復(fù)用就是通過一種機(jī)制,可以監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進(jìn)行相應(yīng)的讀寫操作。
創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括泰山網(wǎng)站建設(shè)、泰山網(wǎng)站制作、泰山網(wǎng)頁(yè)制作以及泰山網(wǎng)絡(luò)營(yíng)銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,泰山網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到泰山省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
但select,poll,epoll本質(zhì)上都是同步I/O ,因?yàn)樗麄兌夹枰谧x寫事件就緒后自己負(fù)責(zé)進(jìn)行讀寫,也就是說這個(gè)讀寫過程是阻塞的,而異步I/O則無需自己負(fù)責(zé)進(jìn)行讀寫,異步I/O的實(shí)現(xiàn)會(huì)負(fù)責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶空間。
I/O復(fù)用模型會(huì)用到select、poll、epoll函數(shù):對(duì)一個(gè)IO端口,兩次調(diào)用,兩次返回,比阻塞IO并沒有什么優(yōu)越性。但關(guān)鍵是 能實(shí)現(xiàn)同時(shí)對(duì)多個(gè)IO端口進(jìn)行監(jiān)聽。
這幾個(gè)函數(shù)也會(huì)使進(jìn)程阻塞,但是和阻塞I/O所不同的是,這幾個(gè)函數(shù) 可以同時(shí)阻塞多個(gè)I/O操作。而且可以同時(shí)對(duì)多個(gè)讀操作,多個(gè)寫操作的I/O函數(shù)進(jìn)行檢測(cè),直到有數(shù)據(jù)可讀或可寫時(shí),才真正調(diào)用I/O操作函數(shù)。
當(dāng)一個(gè)客戶端連接上服務(wù)器時(shí),服務(wù)器就將其連接的fd加入fd_set集合,等到這個(gè)連接準(zhǔn)備好讀或?qū)懙臅r(shí)候,就通知程序進(jìn)行IO操作,與客戶端進(jìn)行數(shù)據(jù)通信。大部分Unix/Linux 都支持 select 函數(shù),該函數(shù)用于探測(cè)多個(gè)文件描述符的狀態(tài)變化。
(1) 創(chuàng)建所關(guān)注的事件的描述符集合(fd_set),對(duì)于一個(gè)描述符,可以關(guān)注其上面的讀(read)、寫(write)、異常(exception)事件,所以通常,要?jiǎng)?chuàng)建三個(gè)fd_set,一個(gè)用來收集關(guān)注讀事件的描述符,一個(gè)用來收集關(guān)注寫事件的描述符,另外一個(gè)用來收集關(guān)注異常事件的描述符集合。
(2)調(diào)用select()等待事件發(fā)生。這里需要注意的一點(diǎn)是,select的阻塞與是否設(shè)置非阻塞I/O是沒有關(guān)系的。
(3) 輪詢所有fd_set中的每一個(gè)fd,檢查是否有相應(yīng)的事件發(fā)生,如果有,就進(jìn)行處理。
優(yōu)點(diǎn):
相比其他模型,使用 select() 的事件驅(qū)動(dòng)模型只用單線程(進(jìn)程)執(zhí)行,占用資源少,不消耗太多 CPU,同時(shí)能夠?yàn)槎嗫蛻舳颂峁┓?wù)。如果試圖建立一個(gè)簡(jiǎn)單的事件驅(qū)動(dòng)的服務(wù)器程序,這個(gè)模型有一定的參考價(jià)值。
缺點(diǎn):
(1)每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),這個(gè)開銷在fd很多時(shí)會(huì)很大!?。。◤?fù)制大量句柄數(shù)據(jù)結(jié)構(gòu),產(chǎn)生巨大的開銷 )。
(2)同時(shí)每次調(diào)用select都需要在內(nèi)核遍歷傳遞進(jìn)來的所有fd,這個(gè)開銷在fd很多時(shí)也很大?。。。ㄏ拇罅繒r(shí)間去輪詢各個(gè)句柄,才能發(fā)現(xiàn)哪些句柄發(fā)生了事件)。
(3)單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,32位機(jī)默認(rèn)是1024。
(4)select的觸發(fā)方式是水平觸發(fā),應(yīng)用程序如果沒有完成對(duì)一個(gè)已經(jīng)就緒的文件描述符進(jìn)行IO操作,那么之后每次select調(diào)用還是會(huì)將這些文件描述符通知進(jìn)程。
(5)該模型將事件探測(cè)和事件響應(yīng)夾雜在一起,一旦事件響應(yīng)的執(zhí)行體龐大,則對(duì)整個(gè)模型是災(zāi)難性的。
poll庫(kù)是在linux2.1.23中引入的,windows平臺(tái)不支持poll。poll本質(zhì)上和select沒有太大區(qū)別,都是先創(chuàng)建一個(gè)關(guān)注事件的描述符的集合,然后再去等待這些事件發(fā)生,然后再輪詢描述符集合,檢查有沒有事件發(fā)生,如果有,就進(jìn)行處理。因此,poll有著與select相似的處理流程:
(1)select需要為讀、寫、異常事件分別創(chuàng)建一個(gè)描述符集合,最后輪詢的時(shí)候,需要分別輪詢這三個(gè)集合。而poll只需要一個(gè)集合,在每個(gè)描述符對(duì)應(yīng)的結(jié)構(gòu)上分別設(shè)置讀、寫、異常事件,最后輪詢的時(shí)候,可以同時(shí)檢查三種事件。
(2)它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲(chǔ)的。
(1)大量的fd的數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核地址空間之間,而不管這樣的復(fù)制是不是有意義。
(2)poll還有一個(gè)特點(diǎn)是“水平觸發(fā)”,如果報(bào)告了fd后,沒有被處理,那么下次poll時(shí)會(huì)再次報(bào)告該fd。
poll和select,它們的最大的問題就在于效率。它們的處理方式都是創(chuàng)建一個(gè)事件列表,然后把這個(gè)列表發(fā)給內(nèi)核,返回的時(shí)候,再去輪詢檢查這個(gè)列表,這樣在描述符比較多的應(yīng)用中,效率就顯得比較低下了。
epoll是一種比較好的做法,它把描述符列表交給內(nèi)核,一旦有事件發(fā)生,內(nèi)核把發(fā)生事件的描述符列表通知給進(jìn)程,這樣就避免了輪詢整個(gè)描述符列表。
epoll支持水平觸發(fā)和邊緣觸發(fā),最大的特點(diǎn)在于邊緣觸發(fā),它只告訴進(jìn)程哪些fd剛剛變?yōu)榫途w態(tài),并且只會(huì)通知一次。還有一個(gè)特點(diǎn)是,epoll使用“事件”的就緒通知方式,通過epoll_ctl注冊(cè)fd,一旦該fd就緒,內(nèi)核就會(huì)采用類似callback的回調(diào)機(jī)制來激活該fd,epoll_wait便可以收到通知。
epoll與select和poll的調(diào)用接口上的不同:select和poll都只提供了一個(gè)函數(shù)——select或者poll函數(shù)。而epoll提供了三個(gè)函數(shù),epoll_create,epoll_ctl和epoll_wait,epoll_create是創(chuàng)建一個(gè)epoll句柄;epoll_ctl是注冊(cè)要監(jiān)聽的事件類型;epoll_wait則是等待事件的產(chǎn)生。
(1)創(chuàng)建一個(gè)epoll描述符,調(diào)用epoll_create()來完成。epoll_create()有一個(gè)整型的參數(shù)size,用來告訴內(nèi)核,要?jiǎng)?chuàng)建一個(gè)有size個(gè)描述符的事件列表(集合)。
(2)給描述符設(shè)置所關(guān)注的事件,并把它添加到內(nèi)核的事件列表中。這里需要調(diào)用epoll_ctl()來完成。
(3)等待內(nèi)核通知事件發(fā)生,得到發(fā)生事件的描述符的結(jié)構(gòu)列表。該過程由epoll_wait()完成。得到事件列表后,就可以進(jìn)行事件處理了。
(1)沒有最大并發(fā)連接的限制,能打開FD的上限遠(yuǎn)大于1024(1G的內(nèi)存上能監(jiān)聽約10萬個(gè)端口);
(2)效率提升。不是輪詢的方式,不會(huì)隨著FD數(shù)目的增加效率下降。只有活躍可用的FD才會(huì)調(diào)用callback函數(shù);
即epoll最大的優(yōu)點(diǎn)就在于它只管你“活躍”的連接,而跟連接總數(shù)無關(guān),因此在實(shí)際的網(wǎng)絡(luò)環(huán)境中,epoll的效率就會(huì)遠(yuǎn)遠(yuǎn)高于select和poll。
(3)內(nèi)存拷貝。epoll通過內(nèi)核和用戶空間共享一塊內(nèi)存來實(shí)現(xiàn)消息傳遞的。利用mmap()文件映射內(nèi)存加速與內(nèi)核空間的消息傳遞;即epoll使用mmap 減少?gòu)?fù)制開銷。epoll保證了每個(gè)fd在整個(gè)過程中只會(huì)拷貝一次(select,poll每次調(diào)用都要把fd集合從用戶態(tài)往內(nèi)核態(tài)拷貝一次)。
參考鏈接:
select、poll、epoll總結(jié)及ET、LT區(qū)別
main.c里面
#include stdio.h
#include stdlib.h
#include "fangkuai.h"
#include time.h
int main()
{
Manager manager;
Control control;
initGame(manager,control);
do {
printPrompting();
printPoolBorder();
runGame(manager,control);
if(ifPlayAgain()){
SetConsoleTextAttribute(Output,0x7);
system("cls");
startGame(manager,control);
}
else{
break;
}
}
while(1);
gotoxyFull(0,0);
CloseHandle(Output);
return 0;
}
.h里面
#ifndef FANGKUAI_H_INCLUDED
#define FANGKUAI_H_INCLUDED
#include stdio.h //標(biāo)準(zhǔn)輸入輸出
#include string.h //字符數(shù)組
#include stdlib.h //標(biāo)準(zhǔn)庫(kù)
#include time.h //日期和時(shí)間
#include conio.h //控制臺(tái)輸入輸出
#include windows.h // windows控制臺(tái)
#include stdbool.h //標(biāo)準(zhǔn)布爾函數(shù)
//定義句柄,結(jié)構(gòu)體,數(shù)組;函數(shù)聲明
//定義方塊數(shù)組,[7][4],7種方塊,每種4個(gè)狀態(tài)
static const unsigned int TetrisTable[7][4]={
{0x4444,0x0f00,0x2222,0x00f0},
{0x04e0,0x4640,0x0720,0x0262},
{0x0446,0x0e80,0x6220,0x0170},
{0x0622,0x02e0,0x4460,0x0740},
{0x0630,0x0264,0x0c60,0x2640},
{0x0462,0x06c0,0x4620,0x0360},
{0x0660,0x0660,0x0660,0x0660},
};
typedef struct TetrisManger{
unsigned int pool[28];
int x;int y;
int type[3];
int orientation[3];
unsigned score;
unsigned erasedCount[4];
unsigned erasedTotal;
unsigned tetrisCount[7];
unsigned tetrisTotal;
bool dead;
}Manager;
static const unsigned int initTetrisPool[28]={
0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,0xc003,
0xc003,0xc003,0xc003,0xc003,0xc003,0xffff,0xffff
};
typedef struct TetresControl{
bool pause;
bool clockwise;
int direction;
int color[28][16];
}Control;
HANDLE Output;
void initGame(Manager *manager,Control *control);
void gotoxyFull(short x,short y);
void printPrompting();
void printPoolBorder();
void printScore(const Manager *manager);
void printNextTetres(const Manager *manager);
void startGame(Manager *manager,Control *control);
void initTetris(Manager *manager);
void insertTetris(Manager *manager);
void setPoolColor(const Manager *manager,Control *control);
void printCurrentTetris(const Manager *manager,const Control *control);
void printTetrisPool(const Manager *manager,const Control *control);
bool checkCollision(const Manager *manager);
void removeTetris(Manager *manager);
void moveDownTetris(Manager *manager,Control *control);
void runGame(Manager *manager,Control *control);
void horzMoveTetris(Manager *manager,Control *control);
void keydownControl(Manager *manager,Control *control,int key);
void rotateTetris(Manager *manager,Control *control);
void dropTetris(Manager *manager,Control *control);
bool checkErasing(Manager *manager,Control *control);
bool ifPlayAgain();
#endif // FANGKUAI_H_INCLUDED
.c里面
#include "fangkuai.h"
#include stdio.h
#include windows.h
void initGame(Manager *manager,Control *control)//初始化游戲
{
SetConsoleTitle("俄羅斯方塊"); //設(shè)置窗口標(biāo)題
Output=GetStdHandle(STD_OUTPUT_HANDLE); //獲取標(biāo)準(zhǔn)輸出句柄
CONSOLE_CURSOR_INFO INFO; //定義光標(biāo)屬性結(jié)構(gòu)體變量
INFO.dwSize=1; //設(shè)置光標(biāo)高度值
INFO.bVisible=FALSE; //設(shè)置光標(biāo)隱藏值
SetConsoleCursorInfo(Output,INFO); //設(shè)置光標(biāo)屬性
startGame(manager,control);
}
//全角定位光標(biāo)
void gotoxyFull(short x,short y) //全角方式定位
{
static COORD cd; //定義結(jié)構(gòu)體變量
cd.X=2*x; //結(jié)構(gòu)體變量 X=2x
cd.Y=y;
SetConsoleCursorPosition(Output,cd);//設(shè)置光標(biāo)位置
}
//顯示右下角按鍵提示信息
void printPrompting(){
SetConsoleTextAttribute(Output,0x0b);//設(shè)置顯示顏色為藍(lán)色光亮
gotoxyFull(26,10);
printf("■控制:");
gotoxyFull(27,12);
printf("□向左移動(dòng):← A 4");
gotoxyFull(27,13);
printf("□向右移動(dòng):→ D 6");
gotoxyFull(27,14);
printf("□向下移動(dòng):↓ S 2");
gotoxyFull(27,15);
printf("□順時(shí)針轉(zhuǎn):↑ W 8");
gotoxyFull(27,16);
printf("□逆時(shí)針轉(zhuǎn):0");
gotoxyFull(27,17);
printf("□直接落地:空格");
gotoxyFull(27,18);
printf("□暫停游戲:回車");
gotoxyFull(26,23);
printf("■BY YU");
}
//顯示游戲池白色邊框
void printPoolBorder(){
SetConsoleTextAttribute(Output,0xF0);//設(shè)置背景色為白色高亮
int y=1;
for (y=1;y23;y++){
gotoxyFull(10,y); //(10,1) 定位到(10,22)
printf("%2s","");
gotoxyFull(23,y); //(23,1)定位到(23,22)
printf("%2s","");
}
gotoxyFull(10,23);//底部一行
printf("%28s",""); //14個(gè)字符,每個(gè)兩位,左邊、右邊白色,中間12
}
//顯示得分、消行數(shù)、方塊數(shù)
void printScore(const Manager *manager){
SetConsoleTextAttribute(Output,0x0E);//設(shè)置顏色為黃色高亮
gotoxyFull(2,2);
printf("■得分:%u",manager-score);
gotoxyFull(1,6);
printf("■消行總數(shù):%u",manager-erasedTotal);
int i;
for (i=0;i4;i++){
gotoxyFull(2,7+i);
printf("□消%d:%u",i+1,manager-erasedCount[i]);
}
gotoxyFull(1,15);
printf("■方塊總數(shù):%u",manager-tetrisTotal);
static const char *tetrisName="ITLJZSO";
for (i=0;i7;i++){
gotoxyFull(2,17+i);
printf("□%c形:%u",tetrisName[i],manager-tetrisCount[i]);
}
}
void printNextTetres(const Manager *manager)//顯示下一個(gè),下下一個(gè)方塊
{
SetConsoleTextAttribute(Output,0x0f);//設(shè)置前景色為白色高亮
gotoxyFull(26,1);
printf("┌─────────┬─────────┐");
gotoxyFull(26,2);
printf("│%9s│%9s│","","");
gotoxyFull(26,3);
printf("│%9s│%9s│","","");
gotoxyFull(26,4);
printf("│%9s│%9s│","","");
gotoxyFull(26,5);
printf("│%9s│%9s│","","");
gotoxyFull(26,6);
printf("└─────────┴─────────┘");
//顯示下一個(gè)方塊
unsigned int tetris ;
int i;
tetris=TetrisTable[manager-type[1]][manager-orientation[1]];
SetConsoleTextAttribute(Output,manager-type[1]|8);
for (i=0;i16;i++){
gotoxyFull(27+(i3),2+(i2));
((tetrisi)0x8000) ? printf("■"):printf("%2s","");
}
tetris=TetrisTable[manager-type[2]][manager-type[2]];
SetConsoleTextAttribute(Output,0x08);
for(i=0;i16;i++){
gotoxyFull(32+(i3),2+(i2));
((tetrisi)0x8000)?printf("■"):printf("%2s","");
}
}
void startGame(Manager *manager,Control *control)//開始游戲
{
memset(manager,0,sizeof(Manager));
memcpy(manager-pool,initTetrisPool,sizeof(unsigned int [28]));//復(fù)制游戲池?cái)?shù)據(jù)
srand((unsigned)time(NULL));//設(shè)置隨機(jī)數(shù)種子
manager-type[1]=rand()%7;//下一個(gè)方塊類型
manager-orientation[1]=rand()%4;//下一個(gè)方塊狀態(tài)
manager-type[2]=rand()%7;//下下一個(gè)方塊類型
manager-orientation[2]=rand()%4;//下下一個(gè)方塊狀態(tài)
memset(control,0,sizeof(Control));//初始化控制結(jié)構(gòu)體為0
initTetris(manager); //初始化方塊
setPoolColor(manager,control);//初始化方塊,若沒有碰撞,插入方塊,需要設(shè)置顏色
}
void initTetris(Manager *manager)//出第一個(gè)方塊
{
unsigned int tetris;
manager-type[0]=manager-type[1];
manager-orientation[0]=manager-orientation[1];
manager-type[1]=manager-type[2];
manager-orientation[1]=manager-orientation[2];
manager-type[2]=rand()%7;
manager-orientation[2]=rand()%4;
tetris=TetrisTable[manager-type[0]][manager-orientation[0]];
manager-x=6;
manager-y=4;
if(checkCollision(manager)){
manager-dead=true;
}
else{
insertTetris(manager);
}
++manager-tetrisTotal;
++manager-tetrisCount[manager-type[0]];
printNextTetres(manager);
printScore(manager);
}
//插入方塊到游戲池
void insertTetris(Manager *manager){
unsigned int tetris=TetrisTable[manager-type[0]][manager-orientation[0]];//相對(duì)于y的位置
manager-pool[manager-y+0]|=(((tetris0x0)0xF000)manager-x);//或等于
manager-pool[manager-y+1]|=(((tetris0x4)0xF000)manager-x);
manager-pool[manager-y+2]|=(((tetris0x8)0xF000)manager-x);
manager-pool[manager-y+3]|=(((tetris0xc)0xF000)manager-x);
}
//設(shè)置游戲顏色
void setPoolColor(const Manager *manager, Control *control){
int i,x,y;
/* i 當(dāng)前方塊值 0----15
x 設(shè)置顏色的列 x=manager-x+3
y 設(shè)置顏色的行 y=manager-y+i2 */
unsigned int tetris;
tetris=TetrisTable[manager-type[0]][manager-orientation[0]];
for(i=0;i16;i++){
y=manager-y+(i2);
if(y25){
break;
}
x=manager-x+(i3);
if((tetrisi)0x8000){
control-color[y][x]=(manager-type[0]|8);
}
}
}
//顯示當(dāng)前方塊
void printCurrentTetris(const Manager *manager,const Control *control){
int x,y;
y=(manager-y4)?(manager-y-1):4;
for (;y26ymanager-y+4;y++){
x=(manager-x2)?(manager-x-1):2;
for (;x14xmanager-x+5;x++) {
gotoxyFull(x+9,y-3);
if((manager-pool[y]x) 0x8000){
SetConsoleTextAttribute(Output,control-color[y][x]);
printf("■");
}
else{
SetConsoleTextAttribute(Output,0);
printf("%2s","");
}
}
}
}
//顯示游戲池
void printTetrisPool(const Manager *manager,const Control *control){
int x,y;
for(y=4;y26;y++)
{
gotoxyFull(11,y-3);
for(x=2;x14;x++)
{
if((manager-pool[y]x) 0x8000)
{
SetConsoleTextAttribute(Output,control-color[y][x]);
printf("■");
}
else {
SetConsoleTextAttribute(Output,0);
printf("%2s","");
}
}
}
}
//碰撞檢測(cè)
bool checkCollision(const Manager *manager){
unsigned int tetris;
tetris=TetrisTable[manager-type[0]][manager-orientation[0]];//準(zhǔn)備插入的當(dāng)前方塊
unsigned int dest;//游戲池中4行4列的值
dest=0;
dest|=(((manager-pool[manager-y+0]manager-x)0xF000)0x0);
dest|=(((manager-pool[manager-y+1]manager-x)0xF000)0x4);//左移x,右移4
dest|=(((manager-pool[manager-y+2]manager-x)0xF000)0x8);
dest|=(((manager-pool[manager-y+3]manager-x)0xF000)0xc);
return((desttetris)!=0);
}
//移除方塊
void removeTetris(Manager *manager){
unsigned int tetris;
tetris=TetrisTable[manager-type[0]][manager-orientation[0]];//準(zhǔn)備插入的當(dāng)前方塊,當(dāng)前方塊值
manager-pool[manager-y+0]=~(((tetris0x0)0xF000)manager-x);//左移0保留 最高,其余清零,右移x,游戲中方塊列位置,取反,原來后面,存
manager-pool[manager-y+1]=~(((tetris0x4)0xF000)manager-x);
manager-pool[manager-y+2]=~(((tetris0x8)0xF000)manager-x);
manager-pool[manager-y+3]=~(((tetris0xc)0xF000)manager-x);
}
//向下移動(dòng)方塊
void moveDownTetris(Manager *manager,Control *control){
int y=manager-y;
removeTetris(manager);
++manager-y;
if(checkCollision(manager)){
manager-y=y;
insertTetris(manager);
if(checkErasing(manager,control))
{
printTetrisPool(manager,control);
}
}
else{
insertTetris(manager);
setPoolColor(manager,control);
printCurrentTetris(manager,control);
}
}
//運(yùn)行游戲
void runGame(Manager *manager,Control *control){
clock_t clockNow,clockLast;
clockLast=clock();
printTetrisPool(manager,control);
while (!manager-dead){
while(_kbhit()){
keydownControl(manager,control,getch());
}
if (!control-pause){
clockNow=clock();
if(clockNow-clockLast0.45F*CLOCKS_PER_SEC){
clockLast=clockNow;
moveDownTetris(manager,control);
}
}
}
}
#includestdio.h
#includestdlib.h
#includetime.h
int main()
{
char pool[]=
{
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t',
'u','v','w','x','y','z','A','B','C','D',
'E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X',
'Y','Z'
};//隨機(jī)池
srand(time(0));
char pwd[9];
pwd[8]='\0';//方便作為字符串輸出處理
int i=0;
while(i!=8)
{
pwd[i++]=pool[rand()%sizeof(pool)];
}
printf("密碼%s",pwd);
}
{
push(s,a[n]);
}
for(n=i-i/2;ni;++n)
{
pop(s,x);
if(x!=a[n])
break;
}
if(print(s))
cout"字符串中心對(duì)稱";
else
cout"字符串中心不對(duì)稱";
}
故障現(xiàn)象
使用多線程的時(shí)候,主函數(shù)尚且還在執(zhí)行,但子函數(shù)卻不執(zhí)行。
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Pool(processes = 4)
for i in range(30):
p.apply_async(func = stitch, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
如圖所示,main會(huì)執(zhí)行,但stitch就不會(huì)了。
原因分析
這是因?yàn)槟愕膮?shù)列表,也就是args和上面stitch函數(shù)的定義不一致。
解決方案
你只要把參數(shù)列表改為一致就可以了。
在C中,正常情況下,我們只能從函數(shù)中返回一個(gè)值。但在有些情況下,我們需要從函數(shù)中返回多個(gè)值,此時(shí)使用數(shù)組或指針能夠很好地完成這樣的任務(wù)。這里是一
個(gè)示例,這個(gè)程序使用一個(gè)整型數(shù)組作為參數(shù),并將數(shù)組元素的和與積返回給調(diào)用函數(shù)。下面是C代碼,這是一種常見情況。下面給出實(shí)現(xiàn)技巧:
1.
#include
2.
#include
3. int*
Pool(int array[],int size)
4.
{
5.
int *x;
6.
int i=0;
7.
int
a[2]={0,1};
8.
for(i=0;i
9.
{
10.
a[0]+=array[i];
// 存儲(chǔ)數(shù)組元素值的和
11.
a[1]*=array[i];
// 存儲(chǔ)數(shù)組元素值的積
12.
}
13. //
將數(shù)組的基地址賦值給整型指針
14.
x=a[0];
15. //
返回整個(gè)數(shù)組
16.
return x;
17. }
18.
19. int main()
20. {
21. int
a[]={1,2,3,4};
22. int
*c; c = Pool(a,4);
23.
printf("Sum = %d\nProduct = %d\n",c[0],c[1]);
24.
getch();
25.
return 0;
26. }
這樣,我們就知道如何使用數(shù)組和指針從C函數(shù)中返回多個(gè)值。在很多情況下你會(huì)發(fā)現(xiàn)這個(gè)技巧很有用。