国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

Linux多線程編程技術(shù)在擲骰子游戲模擬程序中的應(yīng)用

2016-07-02 09:30申時(shí)全廣東科技學(xué)院計(jì)算機(jī)系廣東東莞523000
關(guān)鍵詞:鏈表點(diǎn)數(shù)指針

申時(shí)全(廣東科技學(xué)院計(jì)算機(jī)系,廣東東莞523000)

Linux多線程編程技術(shù)在擲骰子游戲模擬程序中的應(yīng)用

申時(shí)全
(廣東科技學(xué)院計(jì)算機(jī)系,廣東東莞523000)

為了模擬概率事件,針對擲骰子游戲規(guī)則,應(yīng)用Linux系統(tǒng)下C語言多線程機(jī)制以及多個(gè)二值信號量以實(shí)現(xiàn)多個(gè)線程間循環(huán)同步。通過偽隨機(jī)數(shù)模擬擲骰子的點(diǎn)數(shù),設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)基于多線程方式模擬4人擲骰子游戲程序,并對1 000次游戲中每個(gè)游戲者獲勝的次數(shù)進(jìn)行統(tǒng)計(jì)。可以看出,在多次游戲中,每個(gè)游戲者獲勝的概率符合概率分布規(guī)律。程序運(yùn)行結(jié)果表明,利用信號量可有效實(shí)現(xiàn)多個(gè)線程間的同步與互斥,并簡化了程序結(jié)構(gòu)。

多線程;線程同步;隨機(jī)數(shù);擲骰子游戲程序

O 引言

概率事件是日常生活中經(jīng)常會遇到的,如出現(xiàn)某種狀況的可能性,產(chǎn)品出現(xiàn)故障的幾率等。本文通過一個(gè)模擬擲骰子游戲程序來模擬人們在某種博弈規(guī)則下的獲勝概率。采用線程編程模式,用一個(gè)線程模擬一個(gè)游戲者擲下6個(gè)骰子,并按一定規(guī)則給出“叫點(diǎn)”數(shù)。通過1 000次游戲,統(tǒng)計(jì)出每個(gè)游戲者獲勝次數(shù)N,則獲勝概率為N/1 000。

線程是Linux系統(tǒng)的一個(gè)執(zhí)行序列,其處于進(jìn)程中,多個(gè)線程共享同一進(jìn)程的存儲空間和資源。操作系統(tǒng)以進(jìn)程為單位分配資源并進(jìn)行調(diào)度。但在多進(jìn)程并發(fā)運(yùn)行的系統(tǒng)中,進(jìn)程調(diào)度開銷比較大[1]。按一般定義:線程是一個(gè)進(jìn)程內(nèi)部的一個(gè)控制序列。在一個(gè)進(jìn)程中創(chuàng)建新的線程運(yùn)行時(shí),該線程會擁有自己的運(yùn)行棧,并與創(chuàng)建它的線程共享全局變量等系統(tǒng)資源。一個(gè)進(jìn)程中的多個(gè)線程可以處于并發(fā)運(yùn)行狀態(tài)。因此,要使得一個(gè)進(jìn)程中多個(gè)線程有序地工作,并有效地共享資源,就需要在線程之間進(jìn)行有效的同步和互斥控制[2]。Linux系統(tǒng)提供了多種手段實(shí)現(xiàn)進(jìn)程間、線程間的同步和互斥。本文介紹Linux系統(tǒng)下進(jìn)行多線程編程中線程創(chuàng)建、線程掛起、線程同步和互斥等有關(guān)問題,設(shè)計(jì)了一個(gè)模擬4人進(jìn)行擲骰子游戲的程序,說明了多線程編程中的同步與互斥編程技術(shù)。

為了實(shí)現(xiàn)游戲中擲骰子點(diǎn)數(shù)的隨機(jī)性,需要用到偽隨機(jī)數(shù)生成函數(shù)。偽隨機(jī)數(shù)在很多領(lǐng)域中都有應(yīng)用[3]。通過C標(biāo)準(zhǔn)庫中隨機(jī)函數(shù)rand()及相關(guān)函數(shù)的應(yīng)用,給出解決指定范圍隨機(jī)整數(shù)生成通用方法。

通過指定一個(gè)較大的游戲次數(shù)(如1 000),可以統(tǒng)計(jì)出各游戲者獲勝概率,按照隨機(jī)數(shù)的出現(xiàn)概率,則每個(gè)游戲者獲勝次數(shù)相差不會太大(當(dāng)然也會有例外)。

1 Linux多線程編程中的幾個(gè)主要函數(shù)

在Linux系統(tǒng)中,線程系統(tǒng)調(diào)用函數(shù)定義在Pthread.h中[2]。因此在程序中應(yīng)有如下指令:

#inc1ude

1.1 與線程編程相關(guān)的幾個(gè)常用函數(shù)

1.1.1 線程創(chuàng)建函數(shù)

建立線程的函數(shù)Pthread_create(),函數(shù)原型定義為:

int Pthread_create(Pthread_t*tid,const Pthread_attr_t*attr,void *(*start_rtn)(void),void *arg);

參數(shù)tid是一個(gè)指向Pthread_t類型指針,如果創(chuàng)建線程成功,則在該指針?biāo)缸兞恐袑懭刖€程的標(biāo)識符(ID號);參數(shù)attr是指向線程屬性的結(jié)構(gòu)體指針,一般無需設(shè)定,只要設(shè)置為NULL即可;參數(shù)start_rtn用來傳遞一個(gè)函數(shù)地址,該函數(shù)應(yīng)返回一個(gè)任意類型指針,該參數(shù)用一個(gè)定義了的函數(shù)名設(shè)置即可;參數(shù)arg是傳遞給函數(shù)的參數(shù)指針,可以為任何類型。

1.1.2 線程退出函數(shù)

線程退出函數(shù)原型定義為:

void Pthread_exit(void *retva1);

通過調(diào)用該函數(shù)終止線程執(zhí)行,返回一個(gè)指向某對象的指針(注意不能用于返回指向局部變量的指針)。

1.1.3 使線程掛起的函數(shù)

函數(shù)原型定義為:

int Pthread_join(Pthread_t thread,void **thread_rtn);

參數(shù)thread指定要等待的線程;參數(shù)thread_rtn是一個(gè)指針,指向另一個(gè)指針,該指針指向線程返回值。

1.1.4 獲得本線程lD的函數(shù)

函數(shù)原型定義為:

Pthread_t Pthread_se1f(void);

通過調(diào)用該函數(shù),可獲得當(dāng)前執(zhí)行的線程標(biāo)識符(ID號)。

1.1.5 判斷兩個(gè)線程是否為同一線程的函數(shù)

函數(shù)原型定義為:

int Pthread_equa1(Pthread_t Pid1,Pthread_t Pid2);

1.2 線程同步與互斥的幾個(gè)函數(shù)

在Linux系統(tǒng)中,有關(guān)進(jìn)程、線程同步與互斥的手段有多種,這里只涉及有關(guān)的信號量函數(shù)[4]。信號量類型sem_t及相關(guān)函數(shù)定義在semaPhore.h中,因此在程序頭部應(yīng)包含#inc1ude指令。

1.2.1 創(chuàng)建信號量函數(shù)sem_init()

函數(shù)原型定義:

int sem_init(sem_t*sem,int Pshared,unsigned inti va1ue);

該函數(shù)初始化一個(gè)信號量,參數(shù)sem是指向信號量的指針;參數(shù)Pshared為0指示該信號量是當(dāng)前進(jìn)程的局部信號量,在線程編程中,該參數(shù)置為0;參數(shù)va1ue是信號量的值。

1.2.2 控制信號量的函數(shù)

函數(shù)原型定義如下:

int sem_wait(sem_t*sem);int sem_Post(sem_t*sem);

這兩個(gè)函數(shù)分別對信號量sem執(zhí)行P操作和V操作。兩個(gè)函數(shù)的參數(shù)都是一個(gè)sem_t類型指針,指向由sem_init調(diào)用初始化的信號量。

1.2.3 銷毀信號量函數(shù)

函數(shù)原型定義為:

int sem_destroy(sem_t*sem);

用完一個(gè)信號量后應(yīng)銷毀該信號量,并清理相關(guān)資源。該函數(shù)以一個(gè)信號量指針為參數(shù),清理該信號量擁有的所有資源并銷毀這個(gè)信號量。

2 擲骰子游戲模擬程序設(shè)計(jì)技術(shù)

2.1 游戲規(guī)則定義

假定有4個(gè)游戲參與者,每人輪流擲下5個(gè)骰子,然后找出點(diǎn)數(shù)相同最多的點(diǎn)數(shù),例如5個(gè)骰子中,出現(xiàn)最多的是3個(gè)4點(diǎn),那就給出一個(gè)“叫點(diǎn)數(shù)”,這個(gè)叫點(diǎn)數(shù)就是出現(xiàn)相同點(diǎn)數(shù)最多的個(gè)數(shù)加1及點(diǎn)數(shù),如3個(gè)4點(diǎn),則“叫點(diǎn)數(shù)”為(4,4)。規(guī)定所有1點(diǎn)可以代替其他任意點(diǎn)數(shù),如有2個(gè)1點(diǎn),3個(gè)3點(diǎn),則可叫5個(gè)3點(diǎn)。最后總點(diǎn)數(shù)(個(gè)數(shù)乘點(diǎn)數(shù))最大者為獲勝者,若在一輪游戲中,有2個(gè)以上具有相同點(diǎn)數(shù)(最大),則多人同時(shí)獲勝,其余游戲者為失敗。這個(gè)規(guī)則由程序模擬,與實(shí)際游戲中規(guī)則有些不同。

2.2 程序功能定義

該模擬程序應(yīng)先輸入游戲者姓名,然后在屏幕上開列4個(gè)顯示窗口,用于顯示每個(gè)游戲者的點(diǎn)數(shù)分布(5個(gè))、叫點(diǎn)數(shù)、總盤數(shù)、獲勝計(jì)數(shù)值。

2.3 程序?qū)崿F(xiàn)技術(shù)

為了使用戶界面良好,使用Linux系統(tǒng)庫curses支持,使用該庫中的輸出函數(shù)實(shí)現(xiàn)窗口數(shù)據(jù)輸出。另外需要用到如下技術(shù):

(1)鏈表技術(shù)

在許多情況下,使用循環(huán)鏈表作為數(shù)據(jù)存儲便于程序訪問[5]。用一個(gè)單向循環(huán)鏈表存儲游戲用戶的數(shù)據(jù),定義節(jié)點(diǎn)結(jié)構(gòu)如下:

tyPedef struct UserNode{

char name[21]; //用戶名字

int count; //累計(jì)次數(shù)

int score[MAX_NUM]; //存放每次點(diǎn)數(shù)

int win_count; //累計(jì)獲勝次數(shù)

Struct UserNode *next;}Node_tyPe;

把4個(gè)游戲者用戶節(jié)點(diǎn)組成一個(gè)帶頭節(jié)點(diǎn)的循環(huán)鏈表結(jié)構(gòu),如圖1所示。

圖1 游戲者用戶鏈表

(2)安全輸入技術(shù)

為了輸入用戶名,且必須在指定屏幕位置輸入,用戶輸入時(shí)不能超過限定字符個(gè)數(shù)(例如20),否則會出現(xiàn)運(yùn)行錯(cuò)誤。因此不能使用常規(guī)標(biāo)準(zhǔn)庫函數(shù)gets()輸入,而是另外編寫一個(gè)函數(shù)GetString(char*str,int 1en)來實(shí)現(xiàn)。該函數(shù)中,通過調(diào)用Linux系統(tǒng)無回顯字符輸入函數(shù)getch()讀取字符,并排除非法字符,限制輸入字符數(shù)小于或等于參數(shù)1en。其源程序?qū)崿F(xiàn)限于篇幅不再贅述。

(3)輸入游戲者姓名創(chuàng)建用戶鏈表結(jié)構(gòu)

程序中定義一個(gè)用于建立鏈表的函數(shù)Node_tyPe* creat_List(int n),這個(gè)函數(shù)建立具有n個(gè)用戶節(jié)點(diǎn)的循環(huán)鏈表,返回鏈表頭指針。該函數(shù)調(diào)用前面給出的函數(shù)Get-String()輸入游戲者姓名。

(4)生成隨機(jī)數(shù)問題

在C語言的標(biāo)準(zhǔn)庫中定義了隨機(jī)數(shù)生成函數(shù)rand(),用于生成0~RAND_MAX的整數(shù)。程序采用單向函數(shù)反復(fù)迭代,周期性地輸出偽隨機(jī)序列[3]。一般,如果要生成一個(gè)給定范圍(例如1~9)的隨機(jī)數(shù),都會使用如下語句:

rnd_num=rand()%9 +1;

這樣不符合隨機(jī)分布原則。為了防止運(yùn)行程序每次產(chǎn)生的都是同一隨機(jī)數(shù)列,有必要初始化隨機(jī)種子。使用srand((int)time(NULL))來將偽隨機(jī)數(shù)生成器初始化為某一個(gè)不可預(yù)測點(diǎn),在程序初始化時(shí)執(zhí)行。

下面給出一個(gè)用于產(chǎn)生給定范圍的隨機(jī)數(shù)函數(shù)。

int Random Int(int 1ow,int high){

int rnd; doub1e d;

d =(doub1e)rand()/((doub1e)RAND_MAX+1);

rnd =(int)(d*(high -1ow+1));

return rnd;

(5)多窗口顯示技術(shù)

為了在每個(gè)獨(dú)立窗口顯示一個(gè)游戲用戶線程狀態(tài)數(shù)據(jù),需要用到Linux中curses庫,該庫支持頭文件curses.h。支持窗口顯示的有關(guān)函數(shù)定義在這個(gè)頭文件中。下面列出幾個(gè)相關(guān)函數(shù):

創(chuàng)建窗口函數(shù),函數(shù)原型:

W INDOW *newwin(int 1ine,int co1s,int start_y,int start_x);

在窗口指定位置進(jìn)行格式化輸出,函數(shù)原型:

intmvwPrintw(W INDOW *win,int row,int co1,char*format,…);

限于篇幅,其他函數(shù)不再列出。

(6)如何解決程序中線程同步和互斥問題

整個(gè)游戲程序由4個(gè)游戲者用戶線程和一個(gè)主線程構(gòu)成。主線程和4個(gè)游戲者用戶線程的關(guān)系是:主線程做好初始化工作,創(chuàng)建4個(gè)游戲者線程,然后做好初始準(zhǔn)備,進(jìn)入游戲循環(huán)控制。因?yàn)橛螒蛘呔€程一旦創(chuàng)建就會開始執(zhí)行,所以必須處理好主線程與各個(gè)游戲用戶線程之間的同步關(guān)系。每個(gè)線程用2個(gè)信號量實(shí)現(xiàn)同步,通過參數(shù)傳遞方式將信號量傳到線程中,程序中設(shè)置5個(gè)共享的sem _t信號量。同步順序關(guān)系如圖2所示。

圖2 各線程間的同步關(guān)系

對于多線程程序,每個(gè)線程都可并發(fā)運(yùn)行,但對于訪問共享數(shù)據(jù)必須是互斥訪問,即滿足互斥關(guān)系[6]。使用一個(gè)互斥信號量實(shí)現(xiàn)共享數(shù)據(jù)的互斥訪問。主線程必須使第一個(gè)游戲者線程正確進(jìn)入,然后是第二個(gè)、第三個(gè)、第四個(gè)游戲者線程執(zhí)行,產(chǎn)生游戲數(shù)據(jù)并修改了狀態(tài)數(shù)據(jù)后,主線程處理結(jié)果數(shù)據(jù),判定每個(gè)游戲者勝負(fù),修改其獲勝統(tǒng)計(jì)值,然后進(jìn)入下一輪游戲。通過共享一個(gè)全局工作指針work實(shí)現(xiàn)節(jié)點(diǎn)數(shù)據(jù)修改。

3 程序?qū)崿F(xiàn)

對于4個(gè)游戲者線程的實(shí)現(xiàn),可以分別實(shí)現(xiàn)4個(gè)線程控制序列,即定義4個(gè)線程函數(shù)。由于每個(gè)線程行為是一致的,可以在創(chuàng)建線程時(shí)傳遞一個(gè)變量i的指針給線程實(shí)現(xiàn)同步。

創(chuàng)建線程語句:

Pthread_crete(&Pid[i-1],NULL,gamer,(void *)&i);

在屏幕上實(shí)現(xiàn)多窗口顯示效果,顯示游戲者狀態(tài)數(shù)據(jù),程序中模擬4個(gè)游戲者輪流擲骰子MAX_NUM(最多1 000)次,線程負(fù)責(zé)生成5個(gè)隨機(jī)數(shù)(1~6)表示擲下5個(gè)骰子。用一個(gè)全局指針變量work指向每個(gè)線程的信息節(jié)點(diǎn)。一輪游戲結(jié)束,work指針指向頭節(jié)點(diǎn),主線程則在處理一輪游戲的勝負(fù)決斷后,將work指向首節(jié)點(diǎn),開始下一輪游戲。主線程程序結(jié)構(gòu)如圖3所示,游戲者線程程序結(jié)構(gòu)如圖4所示。

圖3 主線程程序結(jié)構(gòu)

圖4 游戲者線程程序結(jié)構(gòu)

運(yùn)行這個(gè)程序需要用到curses庫和Pthread庫,編譯時(shí)使用選項(xiàng)-1Pthread-1curses。經(jīng)過程序運(yùn)行,表明采用的同步控制方法是有效的,獲得了預(yù)期效果。表1所示為其中一組運(yùn)行結(jié)果。

表1 程序運(yùn)行結(jié)果

4 結(jié)論

模擬4人進(jìn)行擲骰子游戲的多線程游戲程序驗(yàn)證了隨機(jī)數(shù)的統(tǒng)計(jì)性能,也說明了多線程編程方法的可行性。通過多線程編程可以很好地解決并發(fā)性問題[6]。本文給出的模擬程序工作模式,對于具有多個(gè)循環(huán)控制對象的系統(tǒng)的應(yīng)用編程具有參考價(jià)值[7],只要將相關(guān)操作語句更換成循環(huán)控制節(jié)點(diǎn)對象的控制(測量)操作即可,其程序采用的多線程同步方法是通用的[8]。另外,如果將此程序移植到網(wǎng)絡(luò)模式,每個(gè)線程改為與實(shí)際游戲者進(jìn)行通信的程序語句方式,就可以實(shí)現(xiàn)網(wǎng)絡(luò)下的游戲程序,可以把叫點(diǎn)過程改為接收遠(yuǎn)程游戲者輸入的叫點(diǎn)數(shù)。當(dāng)然,要實(shí)現(xiàn)網(wǎng)絡(luò)模式下的游戲程序還有許多工作要做。在具有多核處理器情況下采用多線程編程將會獲得更高的運(yùn)行效率。

[1]何宏宇,劉正熙,陳正茂.基于Linux的多進(jìn)程MDSL研究與設(shè)計(jì)[J].四川大學(xué)學(xué)報(bào)(自然科學(xué)版),2013,50(1):46-50.

[2]劉金,胡創(chuàng),胡明,等.多線程環(huán)境下基于多預(yù)取點(diǎn)的文件預(yù)?。跩].計(jì)算機(jī)應(yīng)用,2012,32(6):1713-1716,1720.

[3]高樹靜,曲英杰,宋廷強(qiáng).基于單向函數(shù)的偽隨機(jī)數(shù)發(fā)生器[J].計(jì)算機(jī)研究與發(fā)展,2015,52(6):1394-1399.

[4]彭玉柱.基于多線程機(jī)制的電力數(shù)據(jù)采集系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與軟件,2015,32(1):78-81.

[5]何先波,李明東,王錦,等.Linux操作系統(tǒng)中通用雙向循環(huán)鏈表的實(shí)現(xiàn)分析[J].西華師范大學(xué)學(xué)報(bào)(自然科學(xué)版),2012,33(2):213-217.

[6]謝文斌,陳學(xué)適,姜忠鼎.并行繪制游戲系統(tǒng)中同步傳輸協(xié)議的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用與軟件,2014,31(10):99-103.

[7]趙源,姜小峰.基于多線程技術(shù)的自動(dòng)測試系統(tǒng)優(yōu)化設(shè)計(jì)[J].計(jì)算機(jī)應(yīng)用,2014,34(7):2124-2128.

[8]吳宇佳,浦偉,周妍,等.Linux下多線程數(shù)據(jù)采集研究與實(shí)現(xiàn)[J].信息安全與通信保密,2012(7):92-94.

APP1ication of Linux mu1ti thread Programming techno1ogy in the simu1ation Program of dice game

Shen Shiquan
(DePartment of ComPuter,Guangdong University of Science&Techno1ogy,Dongguan 523000,China)

In order to simu1ate the Probabi1ity events,according to the ru1e of dice game,themu1ti thread mechanism in the C 1anguage under Linux system,and the mu1tiP1e two va1ue semaPhore are aPP1ied to rea1ize cyc1e synchronous among mu1tiP1e threads.The Program simu1ating 4 PeoP1e dice game,which is based on mu1ti thread mode1,is designed and imP1emented.Each P1ayer's winning numbers in 1 000 rounds of the game are ca1cu1ated through simu1ating the Points of the dice with Pseudo random number.As can be seen in the game,each P1ayer has simi1ar winning Probabi1ity in most cases.The resu1ts show that using semaPhores can effective1y achieve synchronization and mutua1exc1usion among mu1tiP1e threads,and can simP1ify the Program structure.

mu1ti thread;thread synchronous;random number;dice game Program

TP311.1

A

10.19358 /j.issn.1674-7720.2016.09.025

申時(shí)全.Linux多線程編程技術(shù)在擲骰子游戲模擬程序中的應(yīng)用[J].微型機(jī)與應(yīng)用,2016,35(9):85-88.

2016-01-14)

申時(shí)全(1953 -),男,本科,教授,主要研究方向:計(jì)算機(jī)應(yīng)用、軟件設(shè)計(jì)技術(shù)。

猜你喜歡
鏈表點(diǎn)數(shù)指針
垂懸指針檢測與防御方法*
基于二進(jìn)制鏈表的粗糙集屬性約簡
跟麥咭學(xué)編程
看不到的總點(diǎn)數(shù)
為什么表的指針都按照順時(shí)針方向轉(zhuǎn)動(dòng)
基于MTF規(guī)則的非阻塞自組織鏈表
C++的基于函數(shù)模板實(shí)現(xiàn)單向鏈表
畫點(diǎn)數(shù)
多核并行的大點(diǎn)數(shù)FFT、IFFT設(shè)計(jì)
淺析C語言指針