并發(fā)程序?qū)嵗?/h2>

所有實(shí)例程序都由C語言編寫

實(shí)測,可運(yùn)行

實(shí)例一

#include <stdio.h>
#include <pthread.h>
void thread(void)
{
  int i;
  for(i=0;i<3;i++)
    printf("This is a pthread.\n");
}
 int main(void)
{
  pthread_t id;//聲明變量
  int i,ret;
  ret=pthread_create(&id,NULL,(void *) thread,NULL); // 成功返回0,錯(cuò)誤返回錯(cuò)誤編號
  if(ret!=0)
    {
    printf ("Create pthread error!\n");
    exit (1);
  }
  for(i=0;i<3;i++)
    {
    printf("This is the main process.\n");
    }
  pthread_join(id,NULL);
  return (0);
}

實(shí)例一分析:函數(shù)pthread_create用來創(chuàng)建一個(gè)線程,第一個(gè)參數(shù)為指向線程標(biāo)識符的指針,第二個(gè)參數(shù)用來設(shè)置線程屬性,第三個(gè)參數(shù)是線程運(yùn)行函數(shù)的起始地址,最后一個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù),函數(shù)pthread_join用來等待一個(gè)線程的結(jié)束,第一個(gè)參數(shù)為被等待的線程標(biāo)識符,第二個(gè)參數(shù)為一個(gè)用戶定義的指針,它可以用來存儲被等待線程的返回值。其中由于線程并發(fā)運(yùn)行順序的不確定性,會引起輸出結(jié)果的隨機(jī)性,這是由于線程爭奪CPU資源造成的。屬于并發(fā)引起的race condition.可以作為并發(fā)實(shí)例。

實(shí)例二:

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

 int count = 0;
 int i = 0;
 int j = 0;
 int k = 0;

/*給i的值和count的值加1*/
void *modify_i_thread(void *data)
{
 for(;;) 
     {
         i++;
         count++;
     }
 }
 
 /*給j的值和count的值加1*/
 void *modify_j_thread(void *data)
 {
     for(;;) {
         j++;
         count++;
     }
 }
 
 /*給k的值和count的值加1*/
 void *modify_k_thread(void *data)
 {
     for(;;) {
         k++;
         count++;
     }
 }
 
 int main(void)
 {
     pthread_t pthid;
     
     /*創(chuàng)建三個(gè)線程    */    
     pthread_create(&pthid, NULL, modify_i_thread, NULL);
     pthread_create(&pthid, NULL, modify_j_thread, NULL);
     pthread_create(&pthid, NULL, modify_k_thread, NULL);
     
     sleep(1);
 
     /*打印結(jié)果    */    
     printf("i = %d, j = %d, k= %d, count = %d\n", i, j, k, count);
     printf("i+j+k=%d\n", i + j + k);
     
     return 0;
 }

實(shí)例二分析: 首先來看程序,程序很簡單,就是創(chuàng)建了3個(gè)線程,第一個(gè)線程對i和count加1,第二個(gè)線程對j和count加1,第三個(gè)線程對k和count加1,i,j,k,count初始化都為0,這樣的話,按照邏輯來說,最后i+j+k = count:仔細(xì)分析下創(chuàng)建的線程執(zhí)行的操作,3個(gè)線程中都對count進(jìn)行了++操作,++操作在C語言中看起來是一條語句,實(shí)際上編譯后是3條語句,首先將count的值寫入寄存器,然后對其進(jìn)行加1操作,在接著將寄存器的值讀出,保存在count中。

三個(gè)線程簡稱為A、B、C,如果A剛剛把count的值寫入寄存器中,此時(shí)調(diào)度程序調(diào)度B線程開始運(yùn)行,這個(gè)時(shí)候,B對count進(jìn)行了N次加法操作,此時(shí)count = count+N,此時(shí)調(diào)度程序恢復(fù)執(zhí)行A線程,那么此時(shí)A中保存的count的值卻是是B線程執(zhí)行前的值,此時(shí),A再對count進(jìn)行操作時(shí),就是基于舊的值(其他線程對count進(jìn)行操作前的值),而不是最新的值,所以count的值并不是我們期望中的值。
屬于并發(fā)引起的數(shù)據(jù)競爭問題。(競爭count)

實(shí)例三:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;     //互斥鎖

void *runodd(void *d)
{
        int i=0;

        for(i=1;;i+=2)
        {
                pthread_mutex_lock(&mutex);//上鎖
                printf("奇數(shù):%d\n",i);
                usleep(100);
                pthread_mutex_unlock(&mutex);//解鎖
        }
}
void *runeven(void *d)
{
        int i=0;
        for(i=0;;i+=2)
        {
                pthread_mutex_lock(&mutex);
                printf("偶數(shù):%d\n",i);
                usleep(100);
                pthread_mutex_unlock(&mutex);
        }
}
main()
{
        pthread_t todd,teven;         //定義兩個(gè)線程
        pthread_mutex_init(&m,0);      //創(chuàng)建鎖
        pthread_create(&todd,0,runodd,0);
        pthread_create(&teven,0,runeven,0);
        sleep(5);

        printf("外部強(qiáng)制停止todd線程\n");
        pthread_cancel(todd);

        pthread_join(todd,(void**)0);              //pthread_join()函數(shù),以阻塞的方式等待thread指定的線程結(jié)束
        pthread_join(teven,(void**)0);
        pthread_mutex_destroy(&mutex);              //鎖的釋放
}

實(shí)例三分析: 屬于并發(fā)引起的死鎖問題,強(qiáng)制停止todd線程后,join函數(shù)還在以正常的狀態(tài)等待,會導(dǎo)致teven線程一直死等。

實(shí)例四:

//假如我們要一直讓thread1先執(zhí)行減,thread2執(zhí)行加,執(zhí)行兩個(gè)函數(shù),順序不確定的兩個(gè)線程
#include <stdio.h>
#include <pthread.h>

int i=10;

void *func1(void *param)
{
    while(1)
    {
        if(i>0)
        {
            i--;
            printf("Thread 1::i    is  %d\n",i);
        }else
         {
            break;
        }
    }
    
}
void *func2(void *param)
{
    while(1)
    {
        if(i<10)
        {
            i++;
            printf("Thread 2::i   is  %d\n",i);
        }else
        {
            break;
        }
    }
    
}


int main()
{
    pthread_t threads[2];
    pthread_create(&threads[0],0,func1,0);
    pthread_create(&threads[1],0,func2,0);
    pthread_join(threads[0],0);
    pthread_join(threads[1],0);
    
    return 0;
}

實(shí)例四分析:兩個(gè)函數(shù),我們本想讓函數(shù)一執(zhí)行減法,函數(shù)二執(zhí)行加法,串行下結(jié)果為10---1-----10,但是由于并行,會導(dǎo)致不可知數(shù)據(jù),屬于并發(fā)引起的數(shù)據(jù)競爭錯(cuò)誤。

實(shí)例五:

#include<unistd.h>
#include <stdio.h>
#include<stdlib.h>

int x;

int One()
{
    int y,z;
    x=1;
    y=0;
    if(x>=1)
    {
        y=y+1;
    }
    z=y;
    return (z);//第一個(gè)函數(shù)執(zhí)行結(jié)果z=1
}
int Two()
{
    int y,z;
    x=0;
    y=0;
    if(x<1)
    {
        y=y+2;
    }
    z=y;
    return (z);//第二個(gè)函數(shù)執(zhí)行結(jié)果z=2
}

void main()
{ 
    int pid;
    pid=fork();//,創(chuàng)建新進(jìn)程成功后,系統(tǒng)中出現(xiàn)兩個(gè)基本完全相同的進(jìn)程,這兩個(gè)進(jìn)程執(zhí)行沒有固定的先后順序,哪個(gè)進(jìn)程先執(zhí)行要看系統(tǒng)的進(jìn)程調(diào)度策略。
    if ( pid == 0 ) //返回0證明創(chuàng)建子進(jìn)程成功 
    {
        One();
    }
else {   
        Two(); 
     }
}

實(shí)例五分析:fork()函數(shù)作用:當(dāng)程序調(diào)用fork()函數(shù)并返回成功之后,程序就將變成兩個(gè)進(jìn)程,調(diào)用fork()者為父進(jìn)程,后來生成者為子進(jìn)程。
若成功調(diào)用一次則返回兩個(gè)值,子進(jìn)程返回0,父進(jìn)程返回子進(jìn)程標(biāo)記;否則,出錯(cuò)返回-1。
在復(fù)制時(shí)復(fù)制了父進(jìn)程的堆棧段,所以兩個(gè)進(jìn)程都停留在fork函數(shù)中,等待返回,因此fork函數(shù)會返回兩次,一次是在父進(jìn)程中返回,另一次是在子進(jìn)程中返回
1)在父進(jìn)程中,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID;
2)在子進(jìn)程中,fork返回0;
屬于并發(fā)引起的共享數(shù)據(jù)競爭的問題。

轉(zhuǎn)載請注明出處,程序來自作者本科畢業(yè)設(shè)計(jì)案例

原創(chuàng)作者:撫仙湖的小王子

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口,提供良好的抽象接口。 管理調(diào)度進(jìn)程,并將多個(gè)進(jìn)程對硬件...
    drfung閱讀 3,755評論 0 5
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,632評論 1 32
  • 一. 操作系統(tǒng)概念 操作系統(tǒng)位于底層硬件與應(yīng)用軟件之間的一層.工作方式: 向下管理硬件,向上提供接口.操作系統(tǒng)進(jìn)行...
    月亮是我踢彎得閱讀 6,151評論 3 28
  • 寫在前面的話 代碼中的# > 表示的是輸出結(jié)果 輸入 使用input()函數(shù) 用法 注意input函數(shù)輸出的均是字...
    FlyingLittlePG閱讀 3,208評論 0 9
  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡介】: Python 是一個(gè)...
    _小老虎_閱讀 6,319評論 0 10

友情鏈接更多精彩內(nèi)容