Linux 线程示例,原程序摘自Bruce Molay 的<<Understanding Unix/Linux Programing >>中第十四章的twordcount.c程序,将原来只能用两个线程为两个文件计数扩展为用三个线程为三个文件计数.
程序使用一个条件变量flag,一个互斥锁lock和一个全局变量mailbox来协同三个计数线程同时对三个文件的词数进行计数.主线程需要flag来指示mailbox中有消息,计数线程需要lock来协调对mailbox的写权限,并检查mailbox为空时才可覆盖.
在原来的程序中计数线程使用 pthread_cond_wait来检测mailbox是否为空,若只是单纯的增加线程进行扩展,会造成死锁,主线程和计数线程都在等待flag条件变量,必须将其修改为释放lock和再要求lock才不会造成死锁:
修改段如下:
原来:
修改为:
不可只是将if改为while应付了事.原来的用两个线程处理两个文件的程序最好也改用此段代码.
切记: pthread_cond_wait(&flag,&lock); 释放lock,并等待flag,等到获得flag后会自动等待lock,之后再返回调用函数处.
完整程序:
原书的两计数线程处理两文件程序:
程序使用一个条件变量flag,一个互斥锁lock和一个全局变量mailbox来协同三个计数线程同时对三个文件的词数进行计数.主线程需要flag来指示mailbox中有消息,计数线程需要lock来协调对mailbox的写权限,并检查mailbox为空时才可覆盖.
在原来的程序中计数线程使用 pthread_cond_wait来检测mailbox是否为空,若只是单纯的增加线程进行扩展,会造成死锁,主线程和计数线程都在等待flag条件变量,必须将其修改为释放lock和再要求lock才不会造成死锁:
修改段如下:
原来:
if
( mailbox
!=
NULL )
{
printf("COUNT: oops..mailbox not empty. wait for signal ");
pthread_cond_wait(&flag,&lock);
}
printf("COUNT: oops..mailbox not empty. wait for signal ");
pthread_cond_wait(&flag,&lock);
}
while
(mailbox
!=
NULL)
{ // if the mailbox is not empty,wait
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
// pthread_cond_wait(&flag,&lock);
}
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
// pthread_cond_wait(&flag,&lock);
}
切记: pthread_cond_wait(&flag,&lock); 释放lock,并等待flag,等到获得flag后会自动等待lock,之后再返回调用函数处.
完整程序:
/*******************************************************************
* twordcount.c - thread word counter for two files
* condition variable allows counter fuctions
* to report result early
*/
#include < stdio.h >
#include < stdlib.h >
#include < pthread.h >
#include < ctype.h >
struct arg_set { // two values in one arg
char *fname; // file to examine
int count; // number of words
int thread_id; // thread id
} ;
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,t3;
struct arg_set args1,args2,args3; // two threads
void *count_words(void *); // two argsets
int reports_in = 0;
int total_words = 0;
if(argc != 4) {
fprintf(stderr,"Usage: %s file1 file2 file3 ",argv[0]);
exit(1);
}
pthread_mutex_lock(&lock); // lock the report box now
args1.fname = argv[1];
args1.count = 0;
args1.thread_id = 1;
pthread_create(&t1,NULL,count_words,(void *)&args1);
args2.fname = argv[2];
args2.count = 0;
args2.thread_id = 2;
pthread_create(&t2,NULL,count_words,(void *)&args2);
args3.fname = argv[3];
args3.count = 0;
args3.thread_id = 3;
pthread_create(&t3,NULL,count_words,(void *)&args3);
while(reports_in < 3) {
printf("MAIN: waiting for flag to go up ");
pthread_cond_wait(&flag,&lock); // wait for notify
printf("MAIN: Wow!flag was raised, I have the lock ");
printf("%7d: %s ",mailbox->count,mailbox->fname);
total_words += mailbox->count;
if(mailbox == &args1)
pthread_join(t1,NULL);
if(mailbox == &args2)
pthread_join(t2,NULL);
if(mailbox == &args3)
pthread_join(t3,NULL);
mailbox = NULL;
pthread_cond_signal(&flag);
++reports_in;
}
printf("%7d: total word ",total_words);
return 0;
}
void * count_words( void * a) {
struct arg_set *args = a; // casts arg back to correct type
FILE *fp;
int c,id = args->thread_id,prevc = '';
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%d: waiting to get lock ",id);
pthread_mutex_lock(&lock); // get the mailbox
printf("COUNT%d: have lock,storing data ",id);
while(mailbox != NULL) { // if the mailbox is not empty,wait
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
// pthread_cond_wait(&flag,&lock);
}
mailbox = args; // put ptr to our args there
printf("COUNT%d: rasing flag ",id);
pthread_cond_signal(&flag); // raise the flag
printf("COUNT%d: unlocking box ",id);
pthread_mutex_unlock(&lock); // release the mail box
return NULL;
}
* twordcount.c - thread word counter for two files
* condition variable allows counter fuctions
* to report result early
*/
#include < stdio.h >
#include < stdlib.h >
#include < pthread.h >
#include < ctype.h >
struct arg_set { // two values in one arg
char *fname; // file to examine
int count; // number of words
int thread_id; // thread id
} ;
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,t3;
struct arg_set args1,args2,args3; // two threads
void *count_words(void *); // two argsets
int reports_in = 0;
int total_words = 0;
if(argc != 4) {
fprintf(stderr,"Usage: %s file1 file2 file3 ",argv[0]);
exit(1);
}
pthread_mutex_lock(&lock); // lock the report box now
args1.fname = argv[1];
args1.count = 0;
args1.thread_id = 1;
pthread_create(&t1,NULL,count_words,(void *)&args1);
args2.fname = argv[2];
args2.count = 0;
args2.thread_id = 2;
pthread_create(&t2,NULL,count_words,(void *)&args2);
args3.fname = argv[3];
args3.count = 0;
args3.thread_id = 3;
pthread_create(&t3,NULL,count_words,(void *)&args3);
while(reports_in < 3) {
printf("MAIN: waiting for flag to go up ");
pthread_cond_wait(&flag,&lock); // wait for notify
printf("MAIN: Wow!flag was raised, I have the lock ");
printf("%7d: %s ",mailbox->count,mailbox->fname);
total_words += mailbox->count;
if(mailbox == &args1)
pthread_join(t1,NULL);
if(mailbox == &args2)
pthread_join(t2,NULL);
if(mailbox == &args3)
pthread_join(t3,NULL);
mailbox = NULL;
pthread_cond_signal(&flag);
++reports_in;
}
printf("%7d: total word ",total_words);
return 0;
}
void * count_words( void * a) {
struct arg_set *args = a; // casts arg back to correct type
FILE *fp;
int c,id = args->thread_id,prevc = '';
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%d: waiting to get lock ",id);
pthread_mutex_lock(&lock); // get the mailbox
printf("COUNT%d: have lock,storing data ",id);
while(mailbox != NULL) { // if the mailbox is not empty,wait
pthread_mutex_unlock(&lock);
pthread_mutex_lock(&lock);
// pthread_cond_wait(&flag,&lock);
}
mailbox = args; // put ptr to our args there
printf("COUNT%d: rasing flag ",id);
pthread_cond_signal(&flag); // raise the flag
printf("COUNT%d: unlocking box ",id);
pthread_mutex_unlock(&lock); // release the mail box
return NULL;
}
/* twordcount4.c - threaded word counter for two files.
* - Version 4: condition variable allows counter
* functions to report results early
*/
#include < stdio.h >
#include < pthread.h >
#include < ctype.h >
struct arg_set { /* two values in one arg*/
char *fname; /* file to examine */
int count; /* number of words */
} ;
struct arg_set * mailbox = NULL;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t flag = PTHREAD_COND_INITIALIZER;
main( int ac, char * av[])
{
pthread_t t1, t2; /* two threads */
struct arg_set args1, args2; /* two argsets */
void *count_words(void *);
int reports_in = 0;
int total_words = 0;
if ( ac != 3 ){
printf("usage: %s file1 file2 ", av[0]);
exit(1);
}
pthread_mutex_lock(&lock); /* lock the report box now */
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 ");
pthread_cond_wait(&flag, &lock); /* wait for notify */
printf("MAIN: Wow! flag was raised, I have the lock ");
printf("%7d: %s ", mailbox->count, mailbox->fname);
total_words += mailbox->count;
if ( mailbox == &args1)
pthread_join(t1,NULL);
if ( mailbox == &args2)
pthread_join(t2,NULL);
mailbox = NULL;
pthread_cond_signal(&flag); /* announce state change */
reports_in++;
}
printf("%7d: total words ", total_words);
}
void * count_words( void * a)
{
struct arg_set *args = a; /* cast arg back to correct type */
FILE *fp;
int c, prevc = '';
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: waiting to get lock ");
pthread_mutex_lock(&lock); /* get the mailbox */
printf("COUNT: have lock, storing data ");
if ( mailbox != NULL ){
printf("COUNT: oops..mailbox not empty. wait for signal ");
pthread_cond_wait(&flag,&lock);
}
mailbox = args; /* put ptr to our args there */
printf("COUNT: raising flag ");
pthread_cond_signal(&flag); /* raise the flag */
printf("COUNT: unlocking box ");
pthread_mutex_unlock(&lock); /* release the mailbox */
return NULL;
}
* - Version 4: condition variable allows counter
* functions to report results early
*/
#include < stdio.h >
#include < pthread.h >
#include < ctype.h >
struct arg_set { /* two values in one arg*/
char *fname; /* file to examine */
int count; /* number of words */
} ;
struct arg_set * mailbox = NULL;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t flag = PTHREAD_COND_INITIALIZER;
main( int ac, char * av[])
{
pthread_t t1, t2; /* two threads */
struct arg_set args1, args2; /* two argsets */
void *count_words(void *);
int reports_in = 0;
int total_words = 0;
if ( ac != 3 ){
printf("usage: %s file1 file2 ", av[0]);
exit(1);
}
pthread_mutex_lock(&lock); /* lock the report box now */
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 ");
pthread_cond_wait(&flag, &lock); /* wait for notify */
printf("MAIN: Wow! flag was raised, I have the lock ");
printf("%7d: %s ", mailbox->count, mailbox->fname);
total_words += mailbox->count;
if ( mailbox == &args1)
pthread_join(t1,NULL);
if ( mailbox == &args2)
pthread_join(t2,NULL);
mailbox = NULL;
pthread_cond_signal(&flag); /* announce state change */
reports_in++;
}
printf("%7d: total words ", total_words);
}
void * count_words( void * a)
{
struct arg_set *args = a; /* cast arg back to correct type */
FILE *fp;
int c, prevc = '';
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: waiting to get lock ");
pthread_mutex_lock(&lock); /* get the mailbox */
printf("COUNT: have lock, storing data ");
if ( mailbox != NULL ){
printf("COUNT: oops..mailbox not empty. wait for signal ");
pthread_cond_wait(&flag,&lock);
}
mailbox = args; /* put ptr to our args there */
printf("COUNT: raising flag ");
pthread_cond_signal(&flag); /* raise the flag */
printf("COUNT: unlocking box ");
pthread_mutex_unlock(&lock); /* release the mailbox */
return NULL;
}