線程并發(fā)導致的經(jīng)典“錯誤”案例——C語言

前言:我在上大學時,對并發(fā)可能導致的問題進行了簡單研究,其中下面的代碼屬于過程性結(jié)果,今日復盤拿出共享,希望您費勁找到的程序,能夠發(fā)揮它的作用!
實例1:并發(fā)導致的線程爭奪資源,線程爭奪資源所導致的輸出結(jié)果不唯一。
廢話不多講,上代碼:
#include <stdio.h>
#include <stdlib.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 j;
???? pthread_create(&id,NULL,(void *) thread,NULL);
???? for(j=0;j<3;j++) {
????????? printf("This is the main process.\n");
????? }
???? pthread_join(id,NULL);
????? return (0);
}
實例2:調(diào)用三個線程分別對三個變量進行增加,同時我們用count共享變量來監(jiān)督增加的次數(shù),但是由于線程并發(fā)的無序性,可能不能正確計算增加的次數(shù)。
廢話不多講,上代碼:
//this is a test
#include<stdio.h>
#include<stdlib.h>
#include <signal.h>
#include <unistd.h>
#include<pthread.h>
int count = 0;
int i=0;
int j=0;
int k=0;
void *modify_i_thread(void *data)
{
??? for(i=0;i<100;i++)
?? {
?????? i++;
?????? count++;
??? }
}
void *modify_j_thread(void *data)
{
???? for(j=0;j<100;j++)
??? {
?????? j++;
?????? count++;
???? }
}
void *modify_k_thread(void *data)
{
??? for(k=0;k<100;k++)
?? {
????? k++;
????? count++;
?? }
}
int main(void)
{
?? int a,b;
?? pthread_t pthid;
?
?? 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);
?? for(a=0;a<i+j+k;a++)
? ??? ?{
? ??? ?b=(i+j+k)/count;
? ??? ?count--;
? ??? ?}
?? return 0;
}
實例3:調(diào)用兩個線程分別對奇數(shù)偶數(shù)進行計數(shù),但是我們在強行關(guān)閉了其中一個線程,會導致死鎖。
廢話不多講,上代碼:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.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("odd:%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("even:%d\n",i);
???????????? usleep(100);
???????????? pthread_mutex_unlock(&mutex);
??????? }
}
int main()
{
??????? pthread_t todd,teven;
??????? pthread_mutex_init(&mutex,0);
??????? pthread_create(&todd,0,runodd,0);
??????? pthread_create(&teven,0,runeven,0);
??????? sleep(5);
??????? printf("stop todd process\n");
??????? pthread_cancel(todd);
??????? pthread_join(todd,(void**)0);
??????? pthread_join(teven,(void**)0);
??????? pthread_mutex_destroy(&mutex);
}
實例5:執(zhí)行結(jié)果取決于主線程main函數(shù)何時終止,線程thread1、thread2是否能夠來得急執(zhí)行它們的函數(shù)爭奪執(zhí)行權(quán)。
屬于race condition 問題。
廢話不多講,上代碼:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
#include<unistd.h>
int g_Flag=0;
void* thread1(void*);
void* thread2(void*);
int main(int argc, char** argv)
{
?? ?printf("enter main\n");
?? ?pthread_t tid1, tid2;
?? ?int rc1=0, rc2=0;
?? ?rc2 = pthread_create(&tid2, NULL, thread2, NULL);
?? ?if(rc2 != 0)
?? ??? ?printf("%s: %d\n",__func__, strerror(rc2));
?? ?rc1 = pthread_create(&tid1, NULL, thread1, &tid2);
?? ?if(rc1 != 0)
?? ??? ?printf("%s: %d\n",__func__, strerror(rc1));
?? ?printf("leave main\n");
?? ?exit(0);?? ?
}
void* thread1(void* arg)
{
?? ?printf("enter thread1\n");
?? ?printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());
?? ?g_Flag = 1;
?? ?printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());
?? ?printf("leave thread1\n");
?? ?pthread_exit(0);
}
void* thread2(void* arg)
{
?? ?printf("enter thread2\n");
?? ?printf("this is thread2, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());
?? ?g_Flag = 2;
?? ?printf("this is thread1, g_Flag: %d, thread id is %u\n",g_Flag, (unsigned int)pthread_self());
?? ?printf("leave thread2\n");
?? ?pthread_exit(0);
}
以上代碼均可運行,基本覆蓋并發(fā)可能導致的各種情況,如果要對這些錯誤進行檢測,需要用到Spin工具,讀到這里還不走,那么接下來您可能會用到Linux或者Cygwin,安裝Spin(?Spin(Simple Promela Interpreter)是一個流行的開源軟件驗證工具)進行檢測驗證。
希望能夠幫到有緣人吧!
留個贊再走唄!thanks!
注:配圖來自網(wǎng)絡。