在Windows服务中使用线程

时间:2013-07-23 08:46:04

标签: c# windows multithreading windows-services

的问题?我有一个win服务,每分钟执行一个方法,示例代码:

protected override void OnStart(string[] args)
        {

            //Elapsed event
            timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);

            timer.Interval = 60000;

            //enable timer
            timer.Enabled = true;

        }

protected override void OnStop()
        {
            timer.Enabled = false;
        }

 private void OnElapsedTime(object source, ElapsedEventArgs e)
        {

            timer.Enabled = false;

            SEND_DATA_TO_CLIENT();

            timer.Enabled = true;
        }

好的,现在方法SEND_DATA_TO_CLIENT();是一种从数据库收集数据并将其发送到客户端的方法,我必须有第二个方法PROCESS_DATA();一种在将数据发送到客户端之前处理数据的方法,但问题是这两种方法同时在数据库中的相同表上工作,所以我不希望得到数据库锁或其他一些数据库错误,并且使用定时器是方法进入碰撞,一个方法处理数据,另一个方法将数据发送到客户端,但它们必须同时工作,也需要单独工作,有没有办法用线程做这种事情以及如何做?

1 个答案:

答案 0 :(得分:1)

如何摆脱问题的想法可能是双缓冲线程循环。 这是实现游戏循环的一个很好的概念,但它也可以满足您的需求。

您将有一个线程在无限循环中执行PROCESS_DATA,另一个线程在无限循环中执行SEND_DATA_TO_CLIENT。你有两个缓冲区。这可以是包含PROCESS_DATA方法返回的信息的任何类或结构。

首先锁定SEND_DATA_TO_CLIENT循环,直到PROCESS_DATA线程填充buffer_1。然后PROCESS_DATA释放SEND_DATA_TO_CLIENT上的锁并交换缓冲区。现在SEND_DATA_TO_CLIENT拥有填充的缓冲区,并根据需要处理数据。在此过程中,PROCESS_DATA同时处理下一个数据,并等待SEND_DATA_TO_CLIENT完成或解锁SEND_DATA_TO_CLIENT以交换缓冲区。

我希望你理解我的意思。如果没有,我可以为你提供一张照片。

/// <summary>
/// Author: Samuel Egger
/// </summary>
class Program
{
    private static EventWaitHandle swappedWh = new EventWaitHandle(false, EventResetMode.AutoReset);

    private static object lockerA = new object();
    private static object lockerB = new object();

    private static int counter = 0;

    // The queues can be of any type which holds your data e.g. a struct or a class
    private static Queue<string> dataQueueA = new Queue<string>();
    private static Queue<string> dataQueueB = new Queue<string>();

    static void Main(string[] args)
    {
        Thread sendDataToClientThread = new Thread(SendDataToClient);
        Thread processDataThread = new Thread(ProcessData);

        sendDataToClientThread.IsBackground = false;

        processDataThread.Start();
        sendDataToClientThread.Start();
    }

    private static void ProcessData()
    {
        while (true)
        {
            lock (lockerA)
            {
                // Your time consuming process goes here. The result then must
                // must be saved (e.g. state) and then enqueued
                dataQueueA.Enqueue(state);
            }

            // If the operations result is equal to 2, then the render thread is done
            // and is waitung for getting unblocked
            if (Interlocked.Increment(ref counter) == 2)
            {
                counter = 0;
                SwapQueues();
                swappedWh.Set();
            }
            else
            {
                swappedWh.WaitOne();
            }
        }
    }

    private static void SendDataToClient()
    {
        while (true)
        {
            lock (lockerB)
            {
                // Send the data generated by the process data thread
                while (dataQueueB.Count > 0)
                {
                    string data = dataQueueB.Dequeue();
                    // Your process of sending the data goes here
                }
            }

            if (Interlocked.Increment(ref counter) == 2)
            {
                counter = 0;
                SwapQueues();
                swappedWh.Set();
            }
            else
            {
                swappedWh.WaitOne();
            }
        }
    }

    static void SwapQueues()
    {
        // Wait until both threads are "done" before swapping

        lock (lockerA)
        {
            lock (lockerB)
            {
                Queue<string> tmpQueue = dataQueueA;
                dataQueueA = dataQueueB;
                dataQueueB = tmpQueue;
            }
        }
    }
}

我希望这个小巧的例子可以帮助你。