所有實(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ù)競爭的問題。