通过ThreadLocal访问RabbitMQ IModel有任何影响或陷阱吗?

时间:2017-10-16 14:35:29

标签: c# multithreading rabbitmq thread-local-storage

我创建了一个类来促进队列上的简单文本消息传输

public class TextQueueTransmitter
{
    private Func<IModel> channelProvider;
    private IBasicProperties props;
    private string queue;

    public TextQueueTransmitter(Func<IModel> channelProvider, string queue)
    {
        this.queue = queue;
        this.channelProvider = channelProvider;

         //will be called once in a thread
        this.channelProvider().QueueDeclare(queue: queue,
                             durable: false,
                             exclusive: false,
                             autoDelete: false,
                             arguments: null);
        props = this.channelProvider().CreateBasicProperties();
    }

    public void SendMessage(string message)
    {
        var body = Encoding.UTF8.GetBytes(message);
        props.DeliveryMode = 1;

        //will be called multiple times not necessarily in the same thread
        channelProvider().BasicPublish(exchange: "",
            routingKey: queue,
            basicProperties: null,
            body: body);
    }
}

初始化将类似于

IConnection connection = ...
ThreadLocal channelThreadLocal = new ThreadLocal<IModel>(connection.CreateModel);
TextQueueTransmitter transmitter = new TextQueueTransmitter(() => channelThreadLocal.Value, "queue name");

之前我直接将IModel传递给发送器,但在阅读here之后IModel不是线程安全的,我意识到如果我想让TextQueueTransmitter线程安全,我必须重新考虑它。

我的问题是,在ThreadLocal中包装IModel有什么影响吗?例如,如果在构造对象的线程之外的线程中调用SendMessage(),则将在不同的线程上调用QueueDeclareBasicPublish。这会导致任何问题吗?

更新:资源处理

正如塞缪尔在答案中所指出的那样,我想到的是渠道处理问题,但我忘记写了。我计划做的是,在程序终止时调用Dispose()的{​​{1}},希望这将调用基础{{1}的Dispose() }秒。虽然我必须验证,因为ThreadLocal documentation没有指定它是否处理不定对象(如果它们实现了IDisposable)。

这会带来“晃来晃去”的危险。连接,即具有不再运行的特定线程的连接。虽然我不认为这是一个严重的问题,因为所有ThreadLocal实例都是长期存在的对象而我不会过度创建线程。

1 个答案:

答案 0 :(得分:2)

我所预见的最大问题是没有处理模型和泄漏资源。您需要控制它们何时被创建并适当地处理它们。