我正在开发一个应用程序,该应用程序分为瘦客户端和服务器部分,通过 TCP 进行通信。我们经常让服务器向客户端进行异步调用(通知)以报告状态变化。这可以避免服务器浪费太多时间来等待客户端的确认。更重要的是,它避免了死锁。
这种死锁可能会发生如下。假设服务器将同步发送状态更改通知(请注意,这是一个有点构造的示例)。当客户端处理通知时,客户端需要同步向服务器询问信息。但是,服务器无法响应,因为他正在等待问题的答案。
现在,通过异步发送通知可以避免这种死锁,但这会带来另一个问题。当异步调用的速度超过处理速度时,调用队列就会不断增长。如果这种情况持续足够长的时间,呼叫队列将完全满(充满消息)。我的问题是:发生这种情况该怎么办?
我的问题可以总结如下。我真的必须在不阻塞发送通知(冒着淹没消息队列的风险)和发送通知时阻塞(冒着引入死锁的风险)之间做出选择吗?有什么技巧可以避免消息队列泛滥吗?
注意:重复一遍,发送通知时服务器不会停止。它们是异步发送的。
注意:在我的示例中,我使用了两个通信进程,但两个通信线程也存在同样的问题。
language-agnostic concurrency multithreading synchronization
Java有编译器检查异常.当我转换到C++时,我了解到它没有检查异常.起初,我一直在使用异常处理,因为它是一个很棒的功能.但是,过了一段时间我放弃了它,因为我遇到了一种情况,每个函数都可能抛出异常.由于我编写的函数中只有一小部分可以抛出异常(比如说最多只有25%),我发现对不能抛出任何不可接受的函数进行异常处理的开销.
因此,我很惊讶有很多开发人员更喜欢未经检查的异常.因此,我很想知道他们是如何处理这个问题的.如果语言不支持检查异常,您如何避免执行不必要的异常处理的开销?
备注:我的问题同样适用于C++和C#,也可能适用于所有其他不具备编译器检查异常处理功能的语言.
可以使用以下步骤注册.DLL,而不是调用regsvr32.exe:
HINSTANCE hLib = ::LoadLibraryEx(dllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
HRESULT (STDAPICALLTYPE* lpDllEntryPoint)(void);
(FARPROC&)lpDllEntryPoint = ::GetProcAddress(hLib, "DllRegisterServer");
const HRESULT hRes = (*lpDllEntryPoint)();
Run Code Online (Sandbox Code Playgroud)
这在Windows XP上运行正常.遗憾的是,它在Vista上失败了,但只有一些特定的DLL.hRes变成E_ACCESSDENIED.我想这是一个安全问题.有谁知道如何从Windows Vista上的代码注册.DLL?
注意:我在运行此代码时以管理员身份登录.
我正在使用Visual Studio 2008 SP1 for C++.编译时,Visual Studio需要选择应该链接应用程序的哪个版本的CRT和MFC DLL,版本9.0.21022.8(= RTM),9.0.30729.17(= SP1)或9.0.30729.4148(=带安全更新的SP1) .我想知道如何选择将两个版本中的哪一个链接起来.有人知道吗?
注意:这在使用专用程序集时很重要,因为您需要知道要与.exe一起复制哪些版本的VC 9.0 DLL.
请注意,_BIND_TO_CURRENT_VCLIBS_VERSION标志仅确保清单中包含正确的版本.运行时的DLL版本选择显然不是基于清单文件中包含的版本完成的.即使清单文件说应该使用v21022,.exe也会使用v30729 .DLL.我知道这一点,因为它使用std :: tr1 :: weakptr,这在v21022中不存在.
当我使用小块中的HttpWebRequest(在Silverlight上)发送/接收数据时,我通过"localhost"连接测量500字节/秒的非常小的吞吐量.当以大块发送数据时,我得到2 MB/s,这快了5000倍.
有谁知道什么可能导致这个令人难以置信的巨大开销?
附加信息:
更新:我使用的Silverlight客户端代码本质上是我自己的WebClient类实现.我写它的原因是因为我注意到WebClient存在相同的性能问题,我认为HttpWebRequest可以调整性能问题.遗憾的是,这没有用.实施如下:
public class HttpCommChannel
{
public delegate void ResponseArrivedCallback(object requestContext, BinaryDataBuffer response);
public HttpCommChannel(ResponseArrivedCallback responseArrivedCallback)
{
this.responseArrivedCallback = responseArrivedCallback;
this.requestSentEvent = new ManualResetEvent(false);
this.responseArrivedEvent = new ManualResetEvent(true);
}
public void MakeRequest(object requestContext, string url, BinaryDataBuffer requestPacket)
{
responseArrivedEvent.WaitOne();
responseArrivedEvent.Reset();
this.requestMsg = requestPacket;
this.requestContext = requestContext;
this.webRequest = WebRequest.Create(url) as HttpWebRequest;
this.webRequest.AllowReadStreamBuffering = true;
this.webRequest.ContentType = …Run Code Online (Sandbox Code Playgroud) 重要更新:显然我在提出这个问题时得出了错误的结论.感谢我发现的响应,lambda函数[=]()在多线程场景中运行良好.我为提出这个令人困惑的问题而道歉.请投票结束,因为这不是问题.
在我们公司,我们编写了一个库函数,在一个单独的线程中异步调用一个函数.它使用继承和模板魔法的组合工作.客户端代码如下所示:
DemoThread thread;
std::string stringToPassByValue = "The string to pass by value";
AsyncCall(thread, &DemoThread::SomeFunction, stringToPassByValue);
Run Code Online (Sandbox Code Playgroud)
自从引入lambda函数以来,我想将它与lambda函数结合使用.我想写下面的客户端代码:
DemoThread thread;
std::string stringToPassByValue = "The string to pass by value";
AsyncCall(thread, [=]()
{
const std::string someCopy = stringToPassByValue;
});
Run Code Online (Sandbox Code Playgroud)
更新:与我在提出这个问题时首先相信的情况相反,此代码运行正常.
现在,使用Visual C++ 2010,此代码不起作用.会发生什么stringToPassByValue是不复制.相反,"按值捕获"功能通过引用传递数据.结果是,如果函数在stringToPassByValue超出范围后执行,则应用程序崩溃,因为它的析构函数已经被调用.
所以我想知道:是否可以将数据作为副本传递给lambda函数?
注意:一种可能的解决方案是修改我们的框架以传递lambda参数声明列表中的数据,如下所示:
DemoThread thread;
std::string stringToPassByValue = "The string to pass by value";
AsyncCall(thread, [=](const std::string stringPassedByValue)
{
const std::string someCopy = stringPassedByValue;
}
, stringToPassByValue); …Run Code Online (Sandbox Code Playgroud) 几年前,我们需要一个C++ IPC库来通过TCP进行函数调用.我们选择了一个并在我们的应用中使用它.过了一会儿,很明显它没有提供我们需要的所有功能.在我们软件的下一个版本中,我们将第三方IPC库丢弃,并将其替换为我们自己编写的库.从那时起,我有时会怀疑这是否是一个好的决定,因为它已被证明是相当多的工作,显然感觉就像重新发明轮子.所以我的问题是:代码重用是否有缺点证明这种重新发明的合理性?
微软有意阻止跨平台软件的发生.Windows和Linux之间的不兼容性是人们不会大量迁移到Linux的主要原因.Mono和Moonlight项目都试图消除这个障碍.
因此,我想知道开始在Mono或Moonlight平台上开发是否风险不大,因为微软可能会阻挠这些跨平台的努力.
在编写函数时,我的实现经常看起来像这样:
关键部分是伐木.每个失败的函数都应该在日志中添加简短描述.这样,在处理异常的级别,可以向用户显示详细的错误消息.
例如,考虑一个可以创建新用户帐户的应用程序,并且数据库连接存在问题.以下反向堆栈跟踪结果:
使用例外功能,我将按如下方式实现:
void CreateUser()
{
try {
OpenDatabaseConnection();
}
catch(std::exception& e) {
e.AddLog("Failed to create the new user");
throw;
}
//...
}
Run Code Online (Sandbox Code Playgroud)
使用简单的返回值,我写下以下内容:
bool CreateUser(Log& log)
{
if (!OpenDatabaseConnection(log))
{
log.Add("Failed to create the new user");
return false;
}
//...
return true;
}
Run Code Online (Sandbox Code Playgroud)
我发现两种实现都同样好.因此,我没有看到使用异常的优势.我很清楚异常处理通常被认为是一个有用的功能,但我真的不明白为什么.很久以前,我广泛使用异常处理,但我没有看到它的大优势,所以现在我再也不用它了.因此我的问题:
注意:我使用术语日志记录 "收集对错误的解释,以便稍后可以将其呈现给用户".我宁愿不将该解释存储在日志消息的全局集合中(在内存中,在文件中或在数据库中),因为它直接描述了特定的异常.
更新:感谢您的回复.我知道只有当用户不需要有关错误的详细反馈时,例外才有用.(如果我误解了这个,请纠正我.)
c++ ×3
.net ×2
dll ×2
exception ×2
windows ×2
c# ×1
c++11 ×1
code-reuse ×1
concurrency ×1
deep-copy ×1
dependencies ×1
http ×1
java ×1
lambda ×1
logging ×1
mono ×1
moonlight ×1
performance ×1
silverlight ×1
terminology ×1