• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0

            一.多線程
              1.了解多線程
                解決多任務(wù)實(shí)現(xiàn)。
                歷史上Unix服務(wù)器不支持多線程
                Unix/Linux上實(shí)現(xiàn)多線程有兩種方式:
                 內(nèi)核支持多線程
                 使用進(jìn)程的編程技巧封裝進(jìn)程實(shí)現(xiàn)多線程:輕量級(jí)多線程
                多線程的庫:
                  libpthread.so   -lpthread

                  pthread.h 

              2.創(chuàng)建多線程
                 2.1.代碼?
                    回調(diào)函數(shù)
                 2.2.線程ID?
                    pthread_t
                 2.3.運(yùn)行線程?
                    pthread_create
               int pthread_create(
                 pthread_t *th,//返回進(jìn)程ID
                 const pthread_attr_t  *attr,//線程屬性,為NULL/0,使用進(jìn)程的默認(rèn)屬性
                 void*(*run)(void*),//線程代碼
                 void *data);//傳遞線程代碼的數(shù)據(jù)
            看一個(gè)小例子:


            #include <stdio.h>
            #include <pthread.h>

            void *run(void *data)
            {
                printf("我是線程!\n");
            }
            main()
            {
                pthread_t tid;
                pthread_create(&tid, 0, run, 0);
            }
            運(yùn)行程序,發(fā)現(xiàn)并沒有輸出。為什么呢?請(qǐng)看結(jié)論:
               結(jié)論:
                 1.程序結(jié)束所有子線程就結(jié)束
                   解決辦法:等待子線程結(jié)束
                        sleep/pause
                   int pthread_join(
                     pthread_t tid,//等待子線程結(jié)束
                     void **re);//子線程結(jié)束的返回值

            #include <stdio.h>
            #include <pthread.h>

            void *run(void *data)
            {
                printf("我是線程!\n");
            }
            main()
            {
                pthread_t tid;
                pthread_create(&tid, 0, run, 0);
                //sleep(1);
                pthread_join(tid, (void **)0);
            }
                 2.創(chuàng)建子線程后,主線程繼續(xù)完成系統(tǒng)分配時(shí)間片。
                 3.子線程結(jié)束就是線程函數(shù)返回。
                 4.子線程與主線程有同等優(yōu)先級(jí)別.
            作業(yè):
              寫一個(gè)程序創(chuàng)建兩個(gè)子線程

            #include <stdio.h>
            #include <pthread.h>

            void *run(void *data)
            {
                printf("我是線程!\n");
            }
            void *run2(void *data)
            {
                printf("我是線程2!\n");
            }
            main()
            {
                pthread_t tid;
                pthread_t tid2;
                pthread_create(&tid, 0, run, 0);
                pthread_create(&tid2, 0, run2, 0);
                //sleep(1);
                pthread_join(tid, (void **)0);
                pthread_join(tid2, (void**)0);
            }
             3.線程的基本控制
                線程的狀態(tài):
                  ready->runny->deady
                       |
                     sleep/pause 
                結(jié)束線程?     
                  內(nèi)部自動(dòng)結(jié)束:(建議)
                   return  返回值;(在線程函數(shù)中使用)
                   void pthread_exit(void*);(在任何線程代碼中使用)  

            #include <stdio.h>
            #include <unistd.h>
            #include <pthread.h>
            #include <sched.h>
            void call()  //用一個(gè)函數(shù)來退出線程的時(shí)候,就可以看到return和exit的區(qū)別
            {
                pthread_exit("Kill");  //可以讓線程結(jié)束
                return ; //只能讓函數(shù)退出,并不能讓線程退出
            }
            void* run(void* data)
            {
                while(1)
                {
                    printf("我是線程!%s\n");
                    sched_yield();  //放棄當(dāng)前時(shí)間片。等待下一次執(zhí)行
                    
            //return "hello";
                    pthread_exit("world");        
                }
            }
            main()
            {
                pthread_t  tid;
                char *re;
                pthread_create(&tid,0,run,0);    
                pthread_join(tid,(void**)&re);  //re接收返回值
                printf("%s\n",re);
                
            }
                  外部結(jié)束一個(gè)線程.      
                   pthread_cancel(pthread_t);
            小應(yīng)用: 用多線程來寫7為隨機(jī)數(shù)和當(dāng)前時(shí)間的顯示

            #include <curses.h>
            #include <pthread.h>
            #include <time.h>
            #include <math.h>
            #include <unistd.h>
            #include <stdlib.h>
            #include <stdio.h>
            //全局變量?jī)蓚€(gè)窗體
            WINDOW *wtime,*wnumb;
            pthread_t thnumb,thtime;
            pthread_mutex_t m;
            //線程1:隨機(jī)數(shù)
            void*runnumb(void *d)
            {
                int num;
                while(1)
                {
                    //循環(huán)產(chǎn)生7位隨機(jī)數(shù)
                    num=rand()%10000000;
                    pthread_mutex_lock(&m);
                    //顯示
                    mvwprintw(wnumb,1,2,"%07d",num);
                    //刷新
                    refresh();
                    wrefresh(wnumb);
                    pthread_mutex_unlock(&m);
                    usleep(1);
                }
                return 0;
            }
            //線程2:時(shí)間
            void*runtime(void*d)
            {    
                time_t tt;
                struct tm *t;
                while(1)
                {
                    //循環(huán)取時(shí)間
                    tt=time(0);
                    t=localtime(&tt);
                    pthread_mutex_lock(&m);
                    //顯示
                    mvwprintw(wtime,1,1,"%02d:%02d:%02d",
                        t->tm_hour,t->tm_min,t->tm_sec);
                    //刷新
                    refresh();
                    wrefresh(wtime);
                    pthread_mutex_unlock(&m);
                    usleep(1);
                }
            }    

            main()
            {
                //初始化curses
                initscr();
                curs_set(0);
                noecho();
                keypad(stdscr,TRUE);
                wnumb=derwin(stdscr,3,11,
                        (LINES-3)/2,(COLS-11)/2);
                wtime=derwin(stdscr,3,10,0,COLS-10);
                box(wnumb,0,0);
                box(wtime,0,0);
                refresh();
                wrefresh(wnumb);
                wrefresh(wtime);
                pthread_mutex_init(&m,0);//2
                
            //創(chuàng)建線程1
                pthread_create(&thnumb,0,runnumb,0);
                //創(chuàng)建線程2
                pthread_create(&thtime,0,runtime,0);
                //等待按鍵
                
            //結(jié)束
                getch();
                pthread_mutex_destroy(&m);//3
                delwin(wnumb);
                delwin(wtime);
                endwin();
            }
            4.多線程的問題
                數(shù)據(jù)臟

            #include <stdio.h>
            #include <pthread.h>

            int a=0,b=0;
            void display()
            {
                a++;
                b++;        
                if(a!=b)
                {
                    printf("%d!=%d\n",a,b);
                    a=b=0;
                }
            }
            void *r1()
            {
                while(1)
                {
                    display();
                }
            }

            void *r2()
            {
                while(1)
                {
                    display();
                }
            }
            main()
            {
                pthread_t t1,t2;
                
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                pthread_join(t1,(void**)0);
                pthread_join(t2,(void**)0);
            }
            看上去好像程序沒有問題,但是會(huì)輸出很多很多不相等的a,b數(shù)據(jù),甚至很多a,b相等的也被輸出來了。這就是兩個(gè)線程之前共用數(shù)據(jù)時(shí)的問題。
              
              5.多線程問題的解決
                互斥鎖/互斥量  mutex
                1.定義互斥量pthread_mutex_t
                2.初始化互斥量 默認(rèn)是1 pthread_mutex_init
                3.互斥量操作  置0 phtread_mutex_lock 
                        判定互斥量0:阻塞
                             1:置0,返回
                      置1 pthread_mutex_unlock
                          置1返回
                   強(qiáng)烈要求成對(duì)使用       
                4.釋放互斥量pthread_mutex_destroy

            #include <stdio.h>
            #include <pthread.h>
            //1.定義互斥量
            pthread_mutex_t m;
            int a=0,b=0;
            void display()
            {
                //3.操作互斥量
                pthread_mutex_lock(&m);    
                a++;
                b++;        
                if(a!=b)
                {
                    printf("%d!=%d\n",a,b);
                    a=b=0;
                }
                pthread_mutex_unlock(&m);    
            }
            void *r1()
            {
                while(1)
                {
                    display();
                }
            }

            void *r2()
            {
                while(1)
                {
                    display();
                }
            }
            main()
            {
                pthread_t t1,t2;
                //2. 初始化互斥量
                pthread_mutex_init(&m,0);
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                pthread_join(t1,(void**)0);
                pthread_join(t2,(void**)0);
                //4. 釋放互斥量
                pthread_mutex_destroy(&m);
            }
              結(jié)論:
                 互斥量保證鎖定的代碼一個(gè)線程執(zhí)行,
                 但不能保證必需執(zhí)行完!           
                
                5.在lock與unlock之間,調(diào)用pthread_exit?
                  或者在線程外部調(diào)用pthread_cancel?
                 其他線程被永久死鎖.
                6.pthread_cleanup_push {
                 pthread_cleanup_pop  } 
                 這對(duì)函數(shù)作用類似于atexit
                 注意:
                  這不是函數(shù),而是宏.
                   必須成對(duì)使用

            #include <stdio.h>
            #include <stdlib.h>
            #include <pthread.h>
            pthread_mutex_t m;
            void handle(void *d)
            {
                printf("退出后的調(diào)用!\n");
                pthread_mutex_unlock(&m);
            }

            void* runodd(void *d)
            {
                int i=0;    
                for(i=1;;i+=2)
                {    
                        
                    pthread_cleanup_push(handle,0);  //pthread_exit()和pthread_cancle()以及pthread_cleanup_pop(1)參數(shù)為1時(shí)會(huì)觸發(fā)
                    pthread_mutex_lock(&m);
                    printf("%d\n",i);        
                    pthread_cleanup_pop(1);        //參數(shù)為1就會(huì)彈出handle并執(zhí)行函數(shù),如果參數(shù)為0,則只彈出,不執(zhí)行函數(shù)。        
                }
            }

            void* runeven(void *d)
            {
                int i=0;
                for(i=0;;i+=2)
                {
                    pthread_cleanup_push(handle,0);
                    pthread_mutex_lock(&m);        
                    printf("%d\n",i);        
                    pthread_cleanup_pop(1);
                    
                }
            }


            main()
            {
                pthread_t todd,teven;
                pthread_mutex_init(&m,0);
                pthread_create(&todd,0,runodd,0);
                pthread_create(&teven,0,runeven,0);
                sleep(5);
                pthread_cancel(todd);
                pthread_join(todd,(void**)0);
                pthread_join(teven,(void**)0);
                pthread_mutex_destroy(&m);
            }

             6.多線程的應(yīng)用

            二.多線程同步
              互斥量/信號(hào)/條件量/信號(hào)量/讀寫鎖
               1.sleep與信號(hào)
                pthread_kill向指定線程發(fā)送信號(hào)
                signal注冊(cè)的是進(jìn)程的信號(hào)處理函數(shù).
                
                pthread_kill+sigwait控制進(jìn)程
                1.1.定義信號(hào)集合
                1.2.初始化信號(hào)集合
                1.3.等待信號(hào) 
                1.4.其他線程發(fā)送信號(hào)  
                1.5.清空信號(hào)集合


            #include <stdio.h>
            #include <pthread.h>
            #include <unistd.h>
            #include <signal.h>
            pthread_t t1,t2;
            sigset_t sigs;
            void handle(int s)
            {
                printf("信號(hào)!\n");
            }
            void*r1(void*d)
            {    
                int s;
                while(1)
                {
                    printf("線程--1\n");
                    sigwait(&sigs,&s);
                    printf("接收到信號(hào):%d!\n",s);
                }
            }
            void*r2(void*d)
            {
                
                while(1)
                {
                    printf("線程----2\n");
                    sleep(2);
                    pthread_kill(t1,SIGUSR1);
                }
            }

            main()
            {
                sigemptyset(&sigs);
                //sigaddset(&sigs,SIGUSR1);
                sigfillset(&sigs);
                //signal(SIGUSR1,handle);
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                
                pthread_join(t1,(void**)0);
                pthread_join(t2,(void**)0);
                
                
            }
            案例:
                sigwait實(shí)際處理了信號(hào)
                如果進(jìn)程沒有處理信號(hào),目標(biāo)線程也沒有sigwait
                ,則進(jìn)程會(huì)接收信號(hào)進(jìn)行默認(rèn)處理

            #include <stdio.h>
            #include <stdlib.h>
            #include <pthread.h>
            #include <sched.h>
            sigset_t sigs;
            pthread_t todd,teven;
            void* runodd(void *d)
            {
                int i=0;    
                int s;
                for(i=0;;i+=2)
                {        
                    printf("%d\n",i);                
                    sigwait(&sigs,&s);
                            
                }
            }

            void* runeven(void *d)
            {
                int i=0;
                int s;
                for(i=1;;i+=2)
                {
                    printf("%d\n",i);
                    sleep(1);                
                    pthread_kill(todd,34);        
                }
            }


            main()
            {    
                sigemptyset(&sigs);
                sigaddset(&sigs,34);    
                pthread_create(&todd,0,runodd,0);
                pthread_create(&teven,0,runeven,0);
                pthread_join(todd,(void**)0);
                pthread_join(teven,(void**)0);
                
            }
             2.條件量
                  信號(hào)量類似
                  2.1.定義條件量
                  2.2.初始化條件量
                  2.3.等待條件量 
                  2.4.其他線程修改條件量
                  2.5.釋放條件量
            案例:
               創(chuàng)建兩個(gè)線程.
                一個(gè)線程等待信號(hào)
                一個(gè)線程每隔1秒發(fā)送信號(hào)
                1.使用pause+pthread_kill

            #include <stdio.h>
            #include <pthread.h>
            #include <signal.h>
            pthread_t t1,t2;
            void handle(int s)  //什么也不干。但是可以防止t1沒有sigwait()處理信號(hào),程序異常退出。
            {
            }
            void *r1(void* d)
            {
                while(1)
                {
                    pause();     //pause受信號(hào)影響,不起作用了。所以程序一直循環(huán)打印。
                    printf("活動(dòng)!\n");
                }
            }
            void *r2(void* d)
            {
                while(1)
                {
                    sleep(1);
                    pthread_kill(t1,34);
                }
            }
            main()
            {
                signal(34,handle);
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                pthread_join(t1,(void**)0);
                pthread_join(t2,(void**)0);
            }
            上面這種方式看起來不太好,有一個(gè)怪怪的函數(shù),什么也沒干。下面用sigwait來處理:

            #include <stdio.h>
            #include <pthread.h>
            #include <signal.h>
            pthread_t t1,t2;
            sigset_t sigs;
            void *r1(void* d)
            {
                int s;
                while(1)
                {        
                    sigwait(&sigs,&s);    
                    printf("活動(dòng)!\n");
                }
            }
            void *r2(void* d)
            {
                while(1)
                {        
                    sleep(1);  //sigwait必須先于pthread_kill執(zhí)行,
                                         
            //才能正確接收到信號(hào),不然也會(huì)異常退出。
                                         
            //所以睡眠一會(huì)兒,保證每次kill之前都已經(jīng)wait了。
                    pthread_kill(t1,34);
                }
            }
            main()
            {
                sigemptyset(&sigs);
                sigaddset(&sigs,34);
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                pthread_join(t1,(void**)0);
                pthread_join(t2,(void**)0);
            }
            上面這種方法的缺陷如sleep()后面的注釋。
            看下面條件量的處理:
            條件量則沒有上面的那個(gè)問題,不用等wait先執(zhí)行。 

            #include <stdio.h>
            #include <pthread.h>
            #include <signal.h>
            pthread_t t1,t2;
            pthread_cond_t cond;//1.
            pthread_mutex_t m;
            void *r1(void* d)
            {
                int s;
                while(1)
                {            
                    pthread_cond_wait(&cond,&m);    //在非互斥的線程里面,m參數(shù)形同虛設(shè)。
                                                                                
            //如果在互斥的線程里,m可以解鎖,讓另一個(gè)線程執(zhí)行,
                                                                                
            //并發(fā)出信號(hào)讓wait接收,防止死鎖。
                    printf("活動(dòng)!\n");
                }
            }
            void *r2(void* d)
            {
                while(1)
                {            
                    pthread_cond_signal(&cond);  //條件量不累計(jì),發(fā)多個(gè)也相當(dāng)于一個(gè)的效果。
                    pthread_cond_signal(&cond);
                    pthread_cond_signal(&cond);
                    sleep(10);
                }
            }
            main()
            {
                pthread_mutex_init(&m,0);
                pthread_cond_init(&cond,0);//2
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                pthread_join(t1,(void**)0);
                pthread_join(t2,(void**)0);
                pthread_cond_destroy(&cond);
                pthread_mutex_destroy(&m);
            }
              pthread_cond_*** 與sigwait都是進(jìn)程同步控制
               
               pthread_cond_***穩(wěn)定
               pthread_cond_***在環(huán)境下不會(huì)死鎖.
            課堂練習(xí):
               使用條件量與互斥構(gòu)造死鎖程序.

            #include <stdio.h>
            #include <pthread.h>

            pthread_t t1,t2;
            pthread_mutex_t m1,m2;
            pthread_cond_t c;

            void* r1(void*d)
            {
                while(1)
                {
                    pthread_mutex_lock(&m1);  
                    printf("我是等待!\n");
                    pthread_cond_wait(&c,&m1); //如果這里是m2,則不能解r2的鎖,造成死鎖
                    pthread_mutex_unlock(&m1);
                }
            }

            void* r2(void *d)
            {
                while(1)
                {
                    pthread_mutex_lock(&m1);
                    printf("我是讓你不等待!\n");
                    pthread_cond_signal(&c);        
                    pthread_mutex_unlock(&m1);
                }
            }
            main()
            {
                pthread_cond_init(&c,0);
                pthread_mutex_init(&m1,0);
                pthread_mutex_init(&m2,0);
                
                pthread_create(&t1,0,r1,0);
                pthread_create(&t2,0,r2,0);
                
                pthread_join(t1,0);
                pthread_join(t2,0);
                
                pthread_mutex_destroy(&m2);
                pthread_mutex_destroy(&m1);
                pthread_cond_destroy(&c);
                
            }
            作業(yè):
               1.寫一個(gè)程序:
                 兩個(gè)線程寫數(shù)據(jù)到文件.
                   數(shù)據(jù)格式:日期時(shí)間,線程ID\n
               要求:
                 要求使用互斥, 保證數(shù)據(jù)正確.
                 體會(huì)使用互斥和不使用互斥的異同.
                 
               2.使用curses寫一個(gè)多線程程序
                 開啟26個(gè)線程.每個(gè)線程控制一個(gè)字母在屏幕上掉落
                   建議每隔字母的高度隨機(jī). 

            #include <pthread.h>
            #include <curses.h>
            #include <math.h>
            struct  AChar
            {
                int x;
                int y;
                int speed;
                char a;
            };
            int stop=1;
            pthread_t t[26];
            pthread_t tid;
            pthread_mutex_t m;
            struct AChar  a[26];

            void *run(void *d)
            {    
                int id;
                static idx=-1;
                idx++;
                id=idx;
                while(stop)
                {
                    pthread_mutex_lock(&m);
                    //改變對(duì)象的y坐標(biāo)
                    a[id].y+=a[id].speed;
                    if(a[id].y>=LINES)
                    {
                        a[id].y=rand()%(LINES/4);
                    }
                    pthread_mutex_unlock(&m);
                    sched_yield();        
                    usleep(100000);
                }
            }
            void * update(void *d)
            {
                int i=0;
                while(stop)
                {
                    erase();
                    //繪制屏幕上
                    for(i=0;i<26;i++)
                    {    
                        mvaddch(a[i].y,a[i].x,a[i].a);
                    }
                    //刷屏
                    refresh();
                    usleep(10000);
                }
                
            }

            main()
            {
                int i;
                initscr();
                curs_set(0);
                noecho();
                keypad(stdscr,TRUE);
                for(i=0;i<26;i++)
                {
                    a[i].x=rand()%COLS;
                    a[i].y=rand()%(LINES/4);
                    a[i].speed=1+rand()%3;
                    a[i].a=65+rand()%26;
                }    
                pthread_mutex_init(&m,0);    
                pthread_create(&tid,0,update,0);
                for(i=0;i<26;i++)
                {
                    //隨機(jī)產(chǎn)生字母與位置        
                    pthread_create(&t[i],0,run,0);
                }    
                getch();
                stop=0;
                for(i=0;i<26;i++)
                {
                    //隨機(jī)產(chǎn)生字母與位置        
                    pthread_join(t[i],(void**)0);
                }
                pthread_join(tid,(void**)0);
                pthread_mutex_destroy(&m);
                endwin();    
            }
              3.寫一個(gè)程序:創(chuàng)建兩個(gè)線程
                  一個(gè)線程負(fù)責(zé)找素?cái)?shù).
                  另外一個(gè)線程把素?cái)?shù)保存到文件
                要求:
                  找到以后,通知另外一個(gè)線程保存,停止招素?cái)?shù)
                  線程保存好以后通知素?cái)?shù)查找線程繼續(xù)查找.
                目的:
                  互斥與信號(hào)/條件量作用是不同.

            99久久精品费精品国产| 久久久久久久久66精品片| 久久精品国产亚洲av麻豆图片| 狠狠色狠狠色综合久久| 久久精品国产精品青草app| 久久久久亚洲av成人无码电影| 亚洲精品无码专区久久久| 国产三级精品久久| 99精品国产在热久久| 久久天天躁夜夜躁狠狠| 久久福利青草精品资源站免费 | 亚洲国产成人精品无码久久久久久综合| 久久这里只精品国产99热| 亚洲国产精品无码久久久不卡| 久久久国产精品福利免费| 久久人人爽人人人人爽AV| 国产三级观看久久| 久久777国产线看观看精品| 国产69精品久久久久久人妻精品| 伊人热人久久中文字幕| 国产精品久久久久久搜索| 亚洲精品乱码久久久久久中文字幕| 久久久久香蕉视频| 欧美精品丝袜久久久中文字幕 | 久久青青草视频| 久久精品亚洲男人的天堂| 99久久免费国产精品| 2021久久国自产拍精品| 久久久久久久久久久久中文字幕| 久久精品国产亚洲AV忘忧草18| 久久综合伊人77777| 深夜久久AAAAA级毛片免费看| 久久精品不卡| 四虎亚洲国产成人久久精品| 色综合久久中文字幕综合网| 精品久久久久久无码国产| 亚洲国产婷婷香蕉久久久久久| 国产精品视频久久久| 久久国产精品-久久精品| 久久精品草草草| 久久国产成人午夜aⅴ影院|