1

私の目的は、CPUにバインドされた作業にスレッドプールスレッドを使用しないようにすることです。これにより、IISが新しい要求への応答を停止する状況を回避できます。

以下のコードに問題がありますか?これは安全でクリーンなアプローチですか?何か改善点はありますか?

    private static ConcurrentQueue<Job> Jobs = new ConcurrentQueue<Job>();
    static int threadCount = 0;

    private void QueueJob(Job job)
    {

        lock(Jobs)
        {
            Jobs.Enqueue(job);
            if (threadCount == 0)
            {

                Interlocked.Increment(ref threadCount); 
                var t= new Thread(new ThreadStart(ConsumeQueue));              
                t.Start();

            }
        }



    }
    private void ConsumeQueue()
    {
        while (true)
        {
            lock (Jobs)
            { 
                if (!Jobs.Any())
                {
                    Interlocked.Decrement(ref threadCount);
                    return;
                }
            }

            Job j;

            var jobToDo = Jobs.TryDequeue(out j);

            if (jobToDo)
            {
                DoCPUBoundWork(j);
            }
        }

    }
4

2 に答える 2

2

これがあなたのニーズを満たすべき基本的なキューです:

//sealed so we don't have to implement full IDisposable pattern
sealed class Q:IDisposable
{
    private CancellationTokenSource cts = new CancellationTokenSource();
    private BlockingCollection<Action> queue =
        new BlockingCollection<Action>(new ConcurrentQueue<Action>());

    public Q()
    {
        new Thread(() => RunQueue()).Start();
    }

    private void RunQueue()
    {
        while(!cts.IsCancellationRequested)
        {
            Action action;
            try
            {
                //lovely... blocks until something is available
                //so we don't need to deal with messy synchronization
                action = queue.Take(cts.Token); 
            }
            catch(OperationCanceledException)
            {
                break;
            }
            action();
        }
    }

    public void AddJob(Action action)
    {
        try
        {
            queue.Add(action,cts.Token);
        }
        catch(OperationCanceledException e)
        {
            throw new ObjectDisposedException("Q is disposed",e);
        }
    }

    public void Dispose()
    {
        if(!cts.IsCancellationRequested)
        {
            cts.Cancel();
        }
    }
}

次のように使用します。

Q actionQueue=new Q();
actionQueue.AddJob(() => Console.WriteLine("action1"));
actionQueue.AddJob(() => Console.WriteLine("action2"));
actionQueue.AddJob(() => Console.WriteLine("action3"));
于 2012-12-11T15:32:15.407 に答える
1

エンキュージョブの前にスレッドが終了する可能性があります

lock (Jobs)
{ 
     if (!ResizeJobs.Any())
     {
         Interlocked.Decrement(ref threadCount);
         return;
     }
}

そしてこの後、別のジョブがJobs.Enqueue(job);を実行します。

ワーカースレッドを終了する必要はないと思います。スリープ状態での作業を待つ必要があります

于 2012-12-11T16:04:24.103 に答える