161 lines
3.9 KiB
C++
161 lines
3.9 KiB
C++
#pragma once
|
||
#include "Area.h"
|
||
#include "CmdArea.h"
|
||
#include "CommonThread.h"
|
||
namespace qing {
|
||
namespace lci{
|
||
/* PrintThread 打印线程 */
|
||
class p_th: public CommonThread {
|
||
public:
|
||
/**
|
||
* 构造函数 传入要读取的控制台设备文件描述符,背景画布,以及命令行区域
|
||
*/
|
||
p_th(std::string name, int masterfd, Drawable *back, CmdArea *font)
|
||
: CommonThread(name) {
|
||
this->masterfd = masterfd;
|
||
this->back = back;
|
||
this->font = font;
|
||
}
|
||
|
||
/**
|
||
* 析构函数 关闭线程
|
||
*
|
||
* 我在可控制线程中主要遇到的问题便是线程的自主终止,
|
||
*
|
||
* 在 Python 中似乎是只能实现可控制线程的手动退出的,
|
||
*
|
||
* 我在想是不是在cpp中也做成那样。
|
||
*
|
||
*
|
||
* FIXME(20260108): 啥意思不懂
|
||
*/
|
||
~p_th(){
|
||
|
||
/* 使线程自主关闭 */
|
||
if (this->chk() != lci::SSHUT){
|
||
this->shut();
|
||
}
|
||
|
||
/* 等待线程退出 */
|
||
this->WaitClose();
|
||
|
||
}
|
||
|
||
/**
|
||
* 暂时删除复制构造函数,因为复制出一个与原来线程无关的空白线程似乎没有什么作用
|
||
*
|
||
* 如果让两个变量引用同一个线程,会使得它们在结束的时候出现错误。
|
||
*/
|
||
p_th(p_th&) = delete;
|
||
|
||
|
||
/**
|
||
* 线程睡眠阶段的操作函数,线程等待。
|
||
*
|
||
* suspend() 方法似乎不太稳定,我还得再测试测试。
|
||
*/
|
||
void StopEvent() override {
|
||
this->suspend();
|
||
}
|
||
|
||
/**
|
||
* 线程苏醒之后执行的操作,线程启动。
|
||
*
|
||
* 我不知道为什么要等待1秒。
|
||
*/
|
||
void WakeEvent() {
|
||
|
||
/* 将文件描述符集合清零 */
|
||
FD_ZERO(&read_fds);
|
||
|
||
/* 清空缓存字符串 */
|
||
output = "";
|
||
|
||
/* 设置完毕,线程进入运行态 */
|
||
this->run();
|
||
|
||
}
|
||
|
||
/**
|
||
* 线程运行阶段的循环体,线程运行。
|
||
*
|
||
* 使用 SELECT 进行缓冲区的探测。
|
||
*/
|
||
void LoopEvent() {
|
||
|
||
/* 对可读集合进行清零 */
|
||
//FD_ZERO(&read_fds);
|
||
|
||
/* 设置可读集合 */
|
||
//FD_SET(masterfd, &read_fds);
|
||
|
||
/**
|
||
* 仅在集合中不存在控制台描述符时,才往其中添加该描述符
|
||
*
|
||
* 在这个集合中,应该只会存在这一个文件描述符吧
|
||
*/
|
||
if (!FD_ISSET(masterfd, &read_fds))
|
||
FD_SET(masterfd, &read_fds);
|
||
|
||
/* 设置超时时间 */
|
||
timeout.tv_sec = 0;
|
||
timeout.tv_usec = 10000;
|
||
|
||
int ret = select(masterfd + 1, &read_fds, NULL, NULL, &timeout);
|
||
if (ret == -1) {
|
||
//throw std::runtime_error("select");
|
||
//this->stop();
|
||
return; /* qing(20260108): 为什么不停止 */
|
||
} else if (ret == 0) { /* No data to read 无值可读 */
|
||
if (output == "") return; /* 在空闲时进行打印*/
|
||
font->print((char*)output.c_str(), 0); /* 按次为单位进行刷新应该可以提高效率 20260108(qing): ?*/
|
||
back->flush(font, false);
|
||
output = "";
|
||
} else {
|
||
if (FD_ISSET(masterfd, &read_fds)) { /* 有值可读 */
|
||
nread = read(masterfd, buffer, sizeof(buffer));
|
||
if (nread > 0) {
|
||
buffer[nread] = '\0';
|
||
output += buffer;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 线程执行过后的清理函数,清理资源。
|
||
*
|
||
* 什么也不做。我们在唤醒时并未申请资源。
|
||
*/
|
||
void ClearEvent() {
|
||
;
|
||
}
|
||
|
||
|
||
private:
|
||
|
||
int masterfd; /* 对象中存储的要读取的控制台设备文件描述符。 */
|
||
|
||
Drawable *back; /* 对象中存储的背景画布指针 */
|
||
|
||
CmdArea *font; /* 对象中存储的命令行区域指针 */
|
||
|
||
std::string output; /* 从终端设备中读取的进程输出 */
|
||
|
||
//--------------------------------------------
|
||
/* 下面的变量是为了提高速度,避免重复申请 */
|
||
|
||
fd_set read_fds; /* 文件描述符集合,用于存储 SELECT 返回的可读区域 */
|
||
|
||
struct timeval timeout; /* 时间结构体 用于传入 SELECT 函数的超时时间 */
|
||
|
||
ssize_t nread; /* 这一次从控制台中所读取大小 */
|
||
|
||
char buffer[1024]; /* 存储从控制台中读取字符的缓冲区,一次最多读这么多 */
|
||
|
||
};
|
||
|
||
}
|
||
}
|