Linux POSIX多线程编程遇到的线程同步问题以及缓冲区问题

我写了一个小程序【代码随后贴上】,作用是主线程从一个文件里不断的读取π的值【文件在博文附件里】,并写入大小为10的数组,子线程从这个数组里取得字符并且输出。因为刚开始学多线程,就把信号量和互斥量全用上了,结果很悲哀,死锁了。于是听取群里的朋友的意见,选用经典的 生产者/消费者问题 算法,只使用了三个信号量,终于搞定了。

#include<stdio.h>#include<unistd.h>#include<string.h>#include<stdlib.h>#include<pthread.h>#include<semaphore.h>void *thread_function(void *arg);int worksize=10;//char workarea[worksize];char workarea[10];sem_t sem;//临界区互斥sem_t full;//待输出字符个数sem_t empty;//空闲空间个数int in=0,out=0;int main(){int res;FILE *fp;int ch;pthread_t a_thread;void *thread_result;/////////semaphore init////////res=sem_init(&sem,0,1);if(res!=0){perror(“error:”);exit(1);}res=sem_init(&full,0,0);if(res!=0){perror(“error:”);exit(1);}res=sem_init(&empty,0,worksize);if(res!=0){perror(“error:”);exit(1);}/////////creat thread///////////res=pthread_create(&a_thread,NULL,thread_function,NULL);if(res!=0){perror(“error:”);exit(1);}/////////open file/////////////if((fp=fopen(“/home/mirage/Desktop/program/pie.txt”,”r”))==NULL){perror(“error:”);exit(1);}///////////producer-read from file////////////while(1){sem_wait(&empty);sem_wait(&sem);//critical sectionif((ch=fgetc(fp))==EOF)break;workarea[in]=ch;in=(in+1)%worksize;//sem_post(&sem); //no critical sectionsem_post(&full);}//whilesem_destroy(&sem);sem_destroy(&empty);sem_destroy(&full);fclose(fp);exit(0);}//main///////////consumer-output to terminal////////////void *thread_function(void *arg){printf(“pie=:3.\n”);while(1){sem_wait(&full);sem_wait(&sem);//critical sectionsleep(1);//注意问题!!printf(“%c”,workarea[out]);out=(out+1)%worksize;sem_post(&sem);//no critical sectionsem_post(&empty);}//while}

但是随之而来的问题是,输出太快,那个π文件里面的数字有限,一瞬间就输出完了,哗哗的,我想让它慢点,于是在临界区加了sleep(1),问题出现了,程序输出完pie=:3.之后就无限等待,我一开始以为逻辑问题,以为又死锁了呢,但是这就是经典的算法思路不会出问题,而且不加sleep就正常,,怎么睡了一秒就不正常了呢。怎么回事?

我把问题发到了linuxquestion.org上面,让老外高手看看(其实是我太渣了),然后一人回复说,

可见,全缓冲8192字节。

至于行缓冲区,我也没找到从哪个文件查看,根据参考资料,行缓冲区1024字节。也就是说,我当时是向终端输出,用的行缓冲,一秒钟写入一个,1024秒后行缓冲区满了,屏幕输出,我要等将近20分钟。。。。

下面做几个测试,验证以上的分析:

基于上面的代码,只更改void *thread_function(void *arg)函数部分。

一、向终端输出,使用行缓冲,如果遇到换行符,缓冲区向屏幕输出。

void *thread_function(void *arg){int ent=0;//计数变量printf(“pie=:3.\n”);while(1){sem_wait(&full);sem_wait(&sem);//criticalusleep(20000); //换用usleep,单位毫秒,更精确printf(“%c”,workarea[out]);ent++;//每向行缓冲区写入一个字符,加一if(ent==10){printf(“\n”);ent=0;} //向行缓冲区写入10个字符后,写入回车符out=(out+1)%worksize;sem_post(&sem);//no criticalsem_post(&empty);}//while}

其结果是这样的:

因为我换用了usleep函数,每20000毫秒写入缓冲区一次,速度还是很合适的,你会看到每写入10个字符,遇到一个换行符之后,行缓冲区把这10个字符输出到屏幕一次,所以数据是一行一行出现。如此循环往复。

二、证明行缓冲区大小为1024字节。

听他第二十八次提起童年往事,每年的同一天和他庆祝生日,

Linux POSIX多线程编程遇到的线程同步问题以及缓冲区问题

相关文章:

你感兴趣的文章:

标签云: