一:写作目的:
最近在写网络编程,对于两个或者多个客户端通过服务器进行数据传输时服务器怎样通过线程将不同客户端发来的数据进行分析和转发有很大的迷惑,所以再次学习一遍线程了解多线程之间通信的大体思路。
二:问题:
这个程序用多线程实现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;
}
'''