一:寫作目的:
最近在寫網絡編程,對於兩個或者多個客戶端通過服務器進行數據傳輸時服務器怎樣通過線程將不同客戶端發來的數據進行分析和轉發有很大的迷惑,所以再次學習一遍線程瞭解多線程之間通信的大體思路。
二:問題:
這個程序用多線程實現wc -w 但出了一點小問題不知道爲什麼和系統的wc -w的值不一樣,
wc -w是記錄文件的英文單詞數,我用的是isalpha()函數如果是字母就返回非0 否則就返回0來判斷。
三:程序:
1。程序的目的:計算兩個文件的詞數之和。
2。程序的內在邏輯:
原線程啓動兩個計數線程後調用pthread_cond_wait(&flag, &lock)這個函數有兩個參數,第一個是條件變量指針,第二個是鎖的指針變量,一個線程開始執行,另一個線程必須等待前一個線程將(1)條件變量的信號 pthread_cond_signal(&flag)傳過來,(2)解鎖的信號* pthread_mutex_unlock(&lock)將這兩個信號接收到之後纔可以執行另一個線程。
3。需要的東西:鎖(一個互斥變量),箱子(一個用來存儲數據的變量), 信號(一個條件變量),
鎖:因爲一個進程內的線程共享進程的資源,它的存在是保證在某一時刻只有一個線程對數據進行處理。保證了數據的安全性。
條件變量:因爲線程不同於進程,進程可以掉用wait()等待子進程執行完了之後再執行,但是線程沒有這個東西,就需要條件變量來作爲信號,一個線程執行完了之後告訴另一個線程它可以開始幹活了。
箱子:就是一個結構體,創建函數pthread_create(pthread_t * t1, pthread_attr_t * attr, (void*)fun(void ), (void )arg)的第四個參數把它變成一個結構體它就可以存儲多個數據。
四:注意的地方:
1。調用pthread_cond_wait()函數時必須要調用pthread_mutex_lock(&lock)將你指定的鎖鎖住,因爲等待函數會先將指定的鎖釋放掉,纔會開始等待線程發來的數據,如果不先將鎖鎖住,函數執行的結果不確定。而且等待函數有一個優點它的返回值自動會將鎖鎖住,這樣就可以保證在一個while循環中不用每次調用這個函數時都要給它加鎖。
# include <pthread.h>
# include <ctype.h>
# include <stdlib.h>
struct arg_set{
char *fname;//文件的名字和文件的詞數
int count;
};
struct arg_set * mailbox;//容器
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//鎖
pthread_cond_t flag = PTHREAD_COND_INITIALIZER;//小紅旗
int main(int argc, char *argv[])
{
pthread_t t1, t2;
struct arg_set args1, args2;//屬於兩個線程各自的數據容器
void *count_words(void *);
int reports_in = 0;//記錄線程的個數
int total_words = 0;//記錄總的詞數
if( argc!= 3){
printf("usage: %s file1 file2\n", argv[0]);
exit(1);
}
pthread_mutex_lock(&lock);//現將郵箱鎖起來mZ
args1.count = 0;
args1.fname = argv[1];
pthread_create(&t1, NULL, count_words, (void*)&args1);//結構體的地址
args2.fname = argv[2];
args2.count = 0;
pthread_create(&t2, NULL, count_words, (void *)&args2);//
while( reports_in < 2 )
{
printf("MAIN: Waiting for flag to go up\n");
pthread_cond_wait(&flag, &lock);//開始執行第一個線程線程執行完後自動跳回這裏
printf("MAIN: WOw! flag was raised, i have the lock\n");
printf(" %d : %s\n", mailbox->count, mailbox->fname);
total_words +=mailbox->count;
if( mailbox == &args1 )
pthread_join(t1, NULL);//使得調用線程掛起直到由t1參數指定的線程終止
if( mailbox == &args2)
pthread_join(t2, NULL);
mailbox = NULL;
pthread_cond_signal(&flag);
reports_in++;
}
printf("%7d: total_words\n",total_words);
return 0;
}
void *count_words(void *a)//將一個文件中的中的英文單詞數記錄下來
{
struct arg_set * args = a;
FILE * fp;
int c, prevc = '\0';
if( (fp = fopen(args->fname, "r")) != NULL )
{
while( (c =getc(fp)) != EOF){//打開一個文件之後
// if( !isalnum(c) && isalnum(prevc) )//isalnum如果是字母或數字,返回一個非零數;否則返回爲0
if(!isalpha(c) && isalpha(prevc))//如果是字母就返回一個非零數,否則返回0,這個必須前面是其他字符&&和字母纔在個數上加1
// if(!isalpha(c)) //這個只是記錄非字母字符的個數
args->count++;
prevc = c;
}
fclose(fp);
}
else
perror(args->fname);
printf("COUNT: Waiting to get lock\n");
pthread_mutex_lock(&lock);//只有加鎖後纔可以對箱子裏的數據進行操作
printf("COUNT: have lock, storing data\n");
if( mailbox != NULL )
pthread_cond_wait(&flag, &lock);
mailbox = args;//結構體整體賦值,將第一個線程已經計算好的箱子,付給main中的箱子
printf("COUNT: raitsing flag\n");
pthread_cond_signal(&flag);//升起小紅旗等待中心的人來將數據取走
printf("COUNT: unlocking box\n");
pthread_mutex_unlock(&lock);//解鎖
return NULL;
}
'''