2017-03-31 85 views
0

我在.NET 3.5应用程序中遇到了问题,并且在开始时我想回答 - 不,我无法迁移到.NET 4.5 - 因此无法使用任务并行库。c中的线程管理器#

客户期望: - 当用户进入项目时,应该生成PDF并保存到数据库(当用户点击按钮时,应用程序应该立即响应)。

基于线程池,在那里我委派任务,使我实现了解决方案:

线程池()=> RenderPDF ...

,一切运作良好,但是当客户做测试,火十个不同的项目与巨大的PDF呈现在同一时间,没有任何线程是完整的。

我想问一下,如果是一个好的方法来让一些管理员能够在这个时候只触发一个任务,如果PDF渲染高于某个尺寸? 我正在考虑像队列管理器这样的东西?这是好方法吗?要生成PDF的我使用第三方DLL(XMLTOPDF)。

编辑:

你能再帮忙吗?我一直试图几乎整个晚上,结果是...,没有结果,但我相信,我正在路上,我只需要更多expirenced的人的帮助:)

根据你的意见,我添加了代码的Global.asax:

protected void Application_BeginRequest(Object source, EventArgs e) 
     { 
      if (!Config.Initialized) 
      { 
       ThreadManager.Init(); 
      } 
    } 

这里是我ThreadManager类:

​​3210

当然,你的BlockingQueue类:

public class BlockingQueue<T> 
    { 
     private readonly Queue<T> Queue; 
     private readonly object Lock; 

     public BlockingQueue() 
     { 
      Queue = new Queue<T>(); 
      Lock = new object(); 
     } 

     public void Enqueue(T Item) 
     { 
      lock (Lock) 
      { 

       Queue.Enqueue(Item); 
       Monitor.Pulse(Lock); 
      } 
     } 

     public T Dequeue() 
     { 
      lock (Lock) 
      { 
       while (Queue.Count == 0) 
        Monitor.Wait(Lock); 

       return Queue.Dequeue(); 
      } 
     } 
    } 

最后我的方法,其中新项目添加到队列:

protected void btnGeneratePdf_Click(object sender, EventArgs e) 
    { 


      byte[] arr = new byte[100]; 
      ThreadManager.RenderingQueue.Enqueue(arr); 
      ThreadManager.RenderingQueue.Enqueue(arr); 
      ThreadManager.RenderingQueue.Enqueue(arr); 



     } 
    } 

当先做项目被添加到队列中,排队方法激发Monitor.Pulse(锁定),然后一切都很好。 但是,当添加第二个项目时,Enqueue方法也会触发Monitor.Pulse(锁定),但不幸的是,在StartThread()中的线程已结束。 如何解决它?我想像while(RenderingQueue.Dequeue()),但它不返回布尔。

+0

听起来像是你可能想看看像MSMQ(或一些其他类型的消息队列)。 – dana

+0

这些PDF生成过程是否共享一些资源?数据库,网络,例如.. –

+0

不,他们不如果我理解的很好。 – tylkonachwile

回答

0

是的,“队列管理器”可以在我看来工作。解决方案的关键是只有一个应该允许一次渲染和线程安全应该使用解决方案。

我想借此对异步解决方案不同的方法:

  • 线程池相反的我将专门用于渲染一个特定主题
  • 线程安全相当于Queue<>将是ConcurrentQueue<>。这样GUI(或主)线程可以以同步的方式与渲染线程通信。
  • 在GUI线程上调用将确保渲染线程回调的安全性。

代码

ConcurrentQueue<byte[]> RenderingQueue = new ConcurrentQueue<byte[]>(); 
Thread RenderingThread = new Thread(() => 
{ 
    byte[] ToBeRendered; 

    while (!RenderingQueue.IsEmpty) 
    { 
     if (RenderingQueue.TryDequeue(out ToBeRendered)) 
     { 
      byte[] Rendered = Render(ToBeRendered); 
      Callback(Rendered); // Invoke action on the GUI thread 
     } 
    } 

    Thread.Sleep(50); 
}); 
RenderingThread.Start(); 
  • Render(byte[]) - 通知转换的结果的用户的方法(重要 - 其中PDF生成发生
  • Callback(byte[])该方法调用GUI的操作线)

如果你想将项目添加到队列中,请使用:

RenderingQueue.Enqueue(new byte[] { }); 

.NET 3.5的解决方案:

public class BlockingQueue<T> 
{ 
    private readonly Queue<T> Queue; 
    private readonly object Lock; 

    public BlockingQueue() 
    { 
     Queue = new Queue<T>(); 
     Lock = new object(); 
    } 

    public void Enqueue(T Item) 
    { 
     lock (Lock) 
     { 
      Queue.Enqueue(Item); 
      Monitor.Pulse(Lock); 
     } 
    } 

    public T Dequeue() 
    { 
     lock (Lock) 
     { 
      while (Queue.Count == 0) 
       Monitor.Wait(Lock); 

      return Queue.Dequeue(); 
     } 
    } 
} 

此代码将适合您的需求,因为Dequeue功能会阻止,直到将新项目添加到Queue渲染线程不会不断旋转,而是等待。

用法:

BlockingQueue<byte[]> RenderingQueue = new BlockingQueue<byte[]>(); 
bool IsStopped = false; 

Thread RenderingThread = new Thread(() => 
{ 
    while (!IsStopped) 
    { 
     byte[] ToBeRendered = RenderingQueue.Dequeue(); 

     byte[] Rendered = Render(ToBeRendered); 
     Callback(Rendered); // Invoke action on the GUI thread 

     Thread.Sleep(50); 
    } 
}); 
RenderingThread.Start(); 
+0

坏消息,在.NET 3.5中没有ConcurrentQueue,现在呢?你可以帮忙吗? :) – tylkonachwile

+0

我们发明了自己的线程安全队列:)我更新了我的答案。 –

+0

我们是开发者,这是我们的责任:),感谢您的回放,但我想知道,BlockingQueue 不应该是静态类吗?根据我的第一篇文章,我想只有一个线程同时工作。我不确定,但是,你的解决方案中没有新的线程定义? – tylkonachwile