c++ - XLib - 如何正确取消增量数据传输的过程?
问题描述
我已经阅读了这篇文章并在互联网上的许多其他地方寻找过,但我找不到我的问题的答案。在 C++ 程序中,我有一个类Clipboard
. 此类正在监视 X11 选择事件,并在选择内容发生更改时将其提取到字符串成员中。对于大型选择,X11 使用“INCR 转移”机制。这个过程在上面的链接中有描述。获取大型选择的内容时,我想检查选择大小是否超过某个限制(例如,20 兆字节),如果超过,我不希望获取此选择以避免我的程序消耗的内存不足. 这就是我目前的大致做法:
void Clipboard::fetchLargeSelectionContent()
{
/* We have received a property of type 'INCR' and are now going to start
the read process
Variables ending with '_' are class' private members */
Atom clipboard = XInternAtom(display_, "CLIPBOARD", false);
Atom target = XInternAtom(display_, "UTF8_STRING", false);
unsigned long nItemsToRead = 0;
Atom typeReturned = None;
int formatReturned = 0;
unsigned long nItemsReturned = 0;
unsigned long nBytesRemaining = 0;
unsigned char* dataReturned = nullptr;
// We do not want selection to exceed 20 megabytes
std::string::size_type sizeLimit = 20 * 1024 * 1024;
bool maxSizeExceeded = false;
// Listen for property events on the requestor's(us) window
XSelectInput(display_, window_, PropertyChangeMask);
/* The xlib::getCurrentTime() function is defined in a separate header file
and returns the current X server time */
Time propertyReadTime = xlib::getCurrentTime();
/* Notify the selection owner that we are ready to receive the data
by deleting the property of type 'INCR' */
XDeleteProperty(display_, window_, property_);
while (true)
{
XEvent event{};
XNextEvent(display_, &event);
if (event.type == PropertyNotify &&
event.xproperty.state == PropertyNewValue &&
event.xproperty.display == display_ &&
event.xproperty.window == window_ &&
event.xproperty.time >= propertyReadTime)
{
// Read zero bytes from the property just to get the size of its content
XGetWindowProperty(
display_,
window_,
property_,
0,
0,
false,
target,
&typeReturned,
&formatReturned,
&nItemsReturned,
&nBytesRemaining,
&dataReturned);
XFree(dataReturned);
dataReturned = nullptr;
if (nBytesRemaining == 0)
{
// Transfer completed
XDeleteProperty(display_, window_, property_);
break;
}
nItemsToRead = nBytesRemaining;
propertyReadTime = xlib::getCurrentTime();
// Read the content and delete the property requesting a new data chunk
XGetWindowProperty(
display_,
window_,
property_,
0,
nItemsToRead,
true,
target,
&typeReturned,
&formatReturned,
&nItemsReturned,
&nBytesRemaining,
&dataReturned);
if (!maxSizeExceeded)
{
content_ += std::string(
reinterpret_cast<const char*>(dataReturned),
nItemsReturned);
maxSizeExceeded = content_.size() > sizeLimit;
}
XFree(dataReturned);
dataReturned = nullptr;
}
}
if (maxSizeExceeded)
{
content_.clear();
std::string().swap(content_);
}
XSelectInput(display_, window_, NoEventMask);
}
这种方法有效,但它有一个明显的缺点 - 即使sizeLimit
超过 ,仍然会收到数据,只是不会写入content_
. 但为什么我要接收我不打算存储和使用的数据呢?我需要以某种方式通知选择所有者我不再对接收新数据块感兴趣,并且它应该中止 INCR 传输过程。但我还没有找到办法。我试图简单地替换while (true)
为while (!maxSizeExceeded)
在超出后立即中断循环sizeLimit
. 但似乎选择所有者仍在等待我的程序读取它发送的数据,因为我可以看到系统内存使用量随着每个后续的 500MB 文本数据副本的显着增长。如果使用我的示例中的方法,则不会发生这种情况(读取整个数据,如果数据太大,则忽略它)。
所以,问题就在标题中——如何优雅地(正确地)中止增量数据传输的过程,甚至有什么方法可以做到吗?
解决方案
推荐阅读
- reactjs - React useState:保留元素工厂实例之间的状态
- algorithm - 了解最大独立集问题的 Luby 算法
- azure - YAML 模板中的意外值“资源””
- elasticsearch - 通过 LogStash 批量导入数据
- pandas - 测试 MultiIndex 中的值
- powershell - Get-ChildItem : 拒绝访问路径“C:\WINDOWS\system32\LogFiles\WMI\RtBackup”
- php - 在 php 中批量更新 Mysql 数据库表的最佳方法是什么?
- laravel - 通过刀片将权限从控制器传递给 javascript
- reactjs - 从 header 组件获取 url 参数
- c# - 从 XML 中检索 XElement,而不从 XDcoument 中删除它们