接着上一篇博文,原来双线程,现在为了实现 暂停/继续 功能,又加了一个线程。第三线程使用条件信号量,当用户按下S键,第三线程将检测到,并且将ifpause置为1,然后输出线程将在if语句成立后被条件信号量cond阻塞。
此时第三线程依然运行。
当检测到按下R后,ifpause置为0,并且使用条件信号量唤醒输出线程。
全局采用生产者/消费者算法。保证输出线程和从文件读数字的线程相互合作正确。
第三线程调用的函数kbhit(),前面一堆语句是为了设置终端,以实现输入字符无回显。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include <termios.h>
#include <fcntl.h>
void *kbhit();
void *thread_function(void *arg);
int worksize=10;
//char workarea[worksize];
char workarea[10];
sem_t sem;
sem_t full;
sem_t empty;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥锁*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化条件变量*/
int in=0,out=0;
int ifpause=0;//0--can continue running 1--condition change! need pause
int main()
{
int res;
FILE *fp;
int ch;
pthread_t a_thread,hit_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);}
//(void)signal(SIG);
/kbhit//
res=pthread_create(&hit_thread,NULL,kbhit,NULL);
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
if((ch=fgetc(fp))==EOF)
break;
workarea[in]=ch;
in=(in+1)%worksize;//
sem_post(&sem); //no critical
sem_post(&full);
}//while
sem_destroy(&sem);
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
exit(0);
}//main
///consumer-output to terminal
void *thread_function(void *arg)
{
int ent=0;
printf("pie=:3.\n");
while(1)
{
sem_wait(&full);
sem_wait(&sem); //critical
///
pthread_mutex_lock(&mutex);
if(ifpause==1)//need pause
pthread_cond_wait(&cond,&mutex);/*条件满足,需要等待,阻塞输出进程,之后生产者进程将在sem_wait(&sem)阻塞。*/
pthread_mutex_unlock(&mutex);
//
usleep(80000);
printf("%c",workarea[out]);
fflush(stdout);
ent++;
if(ent==10)
{printf("\n");ent=0;}
out=(out+1)%worksize;
sem_post(&sem); //no critical
sem_post(&empty);
}//while
}
/kbhit()//
void *kbhit()
{
struct termios oldt, newt;
int ch;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
//ch = getchar();
//tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
//fcntl(STDIN_FILENO, F_SETFL, oldf);
while(1){
usleep(20000);
ch=getchar();
pthread_mutex_lock(&mutex);/*锁住互斥量*/
if(ch=='s')
{ifpause=1;}
else if(ch=='r'&&ifpause==1)//already pause but need run
{ ifpause=0;
pthread_cond_signal(&cond);/*条件改变,发送信号,通知输出线程*/
}
pthread_mutex_unlock(&mutex);/*解锁互斥量*/
///
}//while
}