实验来自《UNIX操作系统实验教程》
实验内容:
编写一段程序创建两个子线程,分别对两个文件的字数进行统计,两个线程统计完后写入到子线程与父线程共享的一块内存(变量)中,然后父线程从这一块内存中读取相应的信息。注意线程的同步和互斥。
源代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <ctype.h>
struct arg_set {
char *fname;//检验的文件
int count;//单词计数
};
struct arg_set * mailbox = NULL;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t flag = PTHREAD_COND_INITIALIZER;
int main(int ac,char *av[])
{
pthread_t t1,t2;//两个线程
struct arg_set args1,args2;
void *count_words(void *);
int reports_in=0;
int total_words=0;
if(ac != 3){
printf("usage:%s file1 file2\n",av[0]);
exit(1);
}
pthread_mutex_lock(&lock);//主线程先锁定临界资源
args1.fname=av[1];
args1.count=0;
pthread_create(&t1,NULL,count_words,(void *)&args1);
args2.fname=av[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("%7d: %s\n",mailbox->count,mailbox->fname);//这里的fname指针是这样用的,c语言里,字符串当做数组看,自然取首地址
total_words += mailbox->count;
if(mailbox==&args1)
pthread_join(t1,NULL);
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;//void型可以赋给任何类型,反之不行。这是为了使得arg返回到正确类型上
FILE * fp;
int c,prevc='\0';
if((fp=fopen(args->fname,"r"))!=NULL){
while((c=getc(fp))!=EOF){
if(!isalnum(c) && isalnum(prevc))
args->count++;
prevc=c;
}
fclose(fp);
} else
perror(args->fname);
printf("count(%lu):waiting to get lock\n",pthread_self());
pthread_mutex_lock(&lock);//当前线程获得mailbox这个临界资源
printf("count(%lu):have lock,storing data\n",pthread_self());
if(mailbox!=NULL){
printf("count(%lu):oops..mailbox not empty.wait for signal\n",pthread_self());
pthread_cond_wait(&flag,&lock);//主线程正在对临界资源进行操作,等待主线程唤醒
}
mailbox=args;//地址复制给mailbox
printf("count(%lu):raising flag\n",pthread_self());
pthread_cond_signal(&flag);//这时候,可以唤醒主线程的等待,对mailbox即将锁定
printf("count(%lu):unlocking box\n",pthread_self());
pthread_mutex_unlock(&lock);//子线程解锁mailbox,即释放mailbox,这时候,主线程的cond_wait函数可以对它锁定
return NULL;
}
建两个文件
[huazi@huazi ~]$ cat >pthread_3.tmp1 <<eof
> @1 2$%^$%3
> 4hd
> eof
[huazi@huazi ~]$ cat >pthread_3.tmp2 <<eof
> abcde
> of
> gh
> ij
> 5
> eof
[huazi@huazi ~]$ gcc -lpthread pthread_3.c -o pthread_3.o
[huazi@huazi ~]$ ./pthread_3.o pthread_3.tmp1 pthread_3.tmp2
main:waiting for flag to go up
count(3078351728):waiting to get lock
count(3078351728):have lock,storing data
count(3078351728):raising flag
count(3078351728):unlocking box
main:wow!flag was raised,I have the lock
4: pthread_3.tmp1
main:waiting for flag to go up
count(3067861872):waiting to get lock
count(3067861872):have lock,storing data
count(3067861872):raising flag
count(3067861872):unlocking box
main:wow!flag was raised,I have the lock
5: pthread_3.tmp2
9:total words