我正在尝试修改ZeroMQ多线程服务示例(http://zguide.zeromq.org/cs:mtserver),以便套接字在关闭时无法无限期地延迟。 我无法弄清楚如何通过QueueDevice接口为两个套接字设置Linger值。在其他示例中,我只是为套接字设置“Linger”选项,当上下文关闭时,它们立即退出。在我当前的程序中,工作线程关闭,但主线程无限期挂起......这可能就像使用SetSocketOption一样简单,但我不理解这个方法的LINQ语法(还),而且“SocketOption”枚举不公开
注意:我正在使用Visual Studio 2013 Express与clrzmq的3.0.0-rc1通过NuGet使用以下命令获得:Install-Package clrzmq -Version 3.0.0-rc1
用法:启动程序并按“ENTER”告诉主线程关闭,然后等待工作人员关闭......但主线程将无限期阻塞。
这是我的代码(Program.cs):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
// add ZeroMQ via NuGet like this: Install-Package clrzmq -Version 3.0.0-rc1
using ZeroMQ;
using ZeroMQ.Devices; // for queuing
namespace MTServiceCS
{
class ThreadContext
{
public ZmqContext _zmqContext = null;
public int _threadID = 0;
}
class Program
{
public static bool g_keepRunning = false;
public static void Main(string[] args)
{
Console.WriteLine("Starting MTServiceCS - multi-threaded hello-world - start the HelloWorld clients to test this server.");
using (var context = ZmqContext.Create())
{
using (var queue = new ZeroMQ.Devices.QueueDevice(context, "tcp://*:5555", "inproc://workers", DeviceMode.Threaded))
{
Console.WriteLine("Initializing Queue.");
queue.Initialize();
// TODO: how to set the "Linger" to zero?
// queue.BackendSetup.SetSocketOption(, 0);
// queue.FrontendSetup.SetSocketOption(, 0);
Console.WriteLine("Creating Threads.");
var workerThreads = new Thread[5];
// set to 'false' to tell the workers to shutdown
g_keepRunning = true;
for (int threadID = 0; threadID < workerThreads.Length; threadID++)
{
workerThreads[threadID] = new Thread(WorkerRoutine);
// passing in more than just the ZMQ Context
ThreadContext tc = new ThreadContext();
tc._threadID = threadID;
tc._zmqContext = context;
workerThreads[threadID].Start(tc);
}
Console.WriteLine("Threads created.");
Console.WriteLine("Starting Queue.");
queue.Start();
// we block here in the calling thread until "ENTER" is pressed and then try to shutdown...
Console.WriteLine("Press ENTER to shutdown.");
Console.ReadLine();
// tell the workers to exit, sleep and then exit... or die trying...
Console.WriteLine("Setting 'g_keepRunning' to false to tell workers to shutdown.");
g_keepRunning = false;
Console.WriteLine("HACK: Sleeping for 4 seconds to allow workers to exit");
Thread.Sleep(4000);
Console.WriteLine("Queue finished.");
queue.Stop();
Console.WriteLine("Stopping queue...");
if (queue.IsRunning)
{
Console.WriteLine("Queue is NOT running.");
}
else
{
while (queue.IsRunning)
{
Console.WriteLine("Queue is STILL running? Looping waiting for it to close...");
Thread.Sleep(1000);
}
Console.WriteLine("Queue has stopped running!");
}
Console.WriteLine("Queue stopped.");
queue.Close();
Console.WriteLine("Queue closed.");
}
Console.WriteLine("QueueDevice closed.");
Console.WriteLine("Exiting context...");
}
Console.WriteLine("Press ENTER to exit.");
Console.ReadLine();
} // Main
private static void WorkerRoutine(object threadContext)
{
ThreadContext tc = (ThreadContext)threadContext;
ZmqSocket receiver = tc._zmqContext.CreateSocket(SocketType.REP);
// ZmqSocket receiver = ((ZmqContext)threadContext).CreateSocket(SocketType.REP);
receiver.Connect("inproc://workers");
Console.WriteLine("Thread# " + tc._threadID.ToString() + " starting.");
// Console.WriteLine("Thread# starting.");
// 1-second timeout
TimeSpan tsTimeout = new TimeSpan(0, 0, 1);
while (g_keepRunning)
{
string message = receiver.Receive(Encoding.Unicode, tsTimeout);
if (message != null && message.Length > 0)
{
Console.WriteLine("Message received: " + tc._threadID.ToString() + ": " + message);
Thread.Sleep(1000); // simulate our work here w/ a sleep for 1 second
// receiver.Send("World", Encoding.Unicode);
receiver.Send("World[" + tc._threadID.ToString() + "]", Encoding.Unicode);
// Console.WriteLine("Thread# " + tc._threadID.ToString() + " sending.");
}
else
{
Console.WriteLine("No message received: " + tc._threadID.ToString());
}
}
Console.WriteLine("Thread# " + tc._threadID.ToString() + " exiting.");
}
}
}