是否有可能总是强制使用任务一个新线程? [英] Is it possible always to force a new thread with Task?

查看:102
本文介绍了是否有可能总是强制使用任务一个新线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个新的线程每个 Task.Factory.StartNew 被调用时。现在的问题是如何在不引发异常波纹管运行代码:

 静态无效的主要(字串[] args)
{
INT firstThreadId = 0;

Task.Factory.StartNew(()=> firstThreadId = Thread.CurrentThread.ManagedThreadId);

的for(int i = 0; I< 100;我++)
{
Task.Factory.StartNew(()=>
{
在(真)
{
Thread.sleep代码(1000);
如果(firstThreadId == Thread.CurrentThread.ManagedThreadId)
抛出新的异常(第一个线程被重用。);
}
});
}
Console.Read();
}



编辑:新的代码如果你发表意见第一个语句是没有问题的。但是,如果你拥有它,WOW,消息线程重用写入到控制台。你可以说是因为我真的很困惑解释。

 静态无效的主要(字串[] args)
{
ConcurrentDictionary< INT,INT> startedThreads =新ConcurrentDictionary< INT,INT>();

的for(int i = 0;我小于10;我++)
{
Task.Factory.StartNew(()=>
{
Task.Factory.StartNew(()=>
{
startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.ManagedThreadId,(A,b)=> b);
},TaskCreationOptions.LongRunning);

为(INT J = 0; J< 100; J ++)
{
Task.Factory.StartNew(()=> ;
{
,而(真)
{
Thread.sleep代码(10);
如果(startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId))
Console.WriteLine(线程重用);
}
},TaskCreationOptions.LongRunning);
}
});
}

Console.Read();
}


解决方案

您好,谢谢大家答案。你都得到了+1。所有建议的解决方案并没有为我的情况下工作。的问题是,当你睡觉一个线程将在一定的时间点被重用。上面的人建议:




  • 使用LongRunning =>这不会工作,如果你有嵌套/儿童
    任务

  • 自定义任务计划程序=>我试着写我自己也试过这种
    ThreadPerTaskScheduler 也迪无法正常工作

  • 使用纯线程=>仍然失败...



我的解决方案



我不喜欢它,但它的作品。基本上我阻塞线程,因此它不能被重用。贝娄是扩展方法和工作示例。 。再次感谢您



的https://gist.github .COM / 4150635

 使用系统; 
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用System.Linq的;
使用的System.Threading;使用System.Threading.Tasks
;

命名空间ConsoleApplication
{
公共静态类ThreadExtensions
{
///<总结>
///块当前线程一段时间,以使线程不能由线程池可重复使用。
///< /总结>
公共静态无效块(此主题线,诠释millisecondsTimeout)
{
新WakeSleepClass(millisecondsTimeout).SleepThread();
}

///<总结>
///块当前线程,以使线程不能由线程池可重复使用。
///< /总结>
公共静态无效块(此主题线程)
{
新WakeSleepClass()SleepThread();
}

///<总结>
///块当前线程一段时间,以使线程不能由线程池可重复使用。
///< /总结>
公共静态无效块(此主题线,时间跨度超时)
{
新WakeSleepClass(超时).SleepThread();
}

类WakeSleepClass
{
布尔锁定= TRUE;
只读TimerDisposer timerDisposer =新TimerDisposer();

公共WakeSleepClass(INT睡眠时间)
{
变种定时器=新定时器(WakeThread,timerDisposer,睡眠时间,睡眠时间);
timerDisposer.InternalTimer =定时器;
}

公共WakeSleepClass(时间跨度睡眠时间)
{
变种定时器=新定时器(WakeThread,timerDisposer,睡眠时间,睡眠时间);
timerDisposer.InternalTimer =定时器;
}

公共WakeSleepClass()
{
变种定时器=新定时器(WakeThread,timerDisposer,Timeout.Infinite,Timeout.Infinite);
timerDisposer.InternalTimer =定时器;
}

公共无效SleepThread()
{
,而(锁定)
锁(timerDisposer)Monitor.Wait(timerDisposer);
锁定= TRUE;
}

公共无效WakeThread(对象键)
{
锁定= FALSE;
锁(钥匙)Monitor.Pulse(密钥);
((TimerDisposer)键).InternalTimer.Dispose();
}

类TimerDisposer
{
公共定时器InternalTimer {搞定;组; }
}
}
}

类节目
{
私人静态只读队列< CancellationTokenSource> tokenSourceQueue =新队列< CancellationTokenSource>();
静态无效的主要(字串[] args)
{
CancellationTokenSource tokenSource =新CancellationTokenSource();
tokenSourceQueue.Enqueue(tokenSource);

ConcurrentDictionary< INT,INT> startedThreads =新ConcurrentDictionary< INT,INT>();
的for(int i = 0;我小于10;我++)
{
Thread.sleep代码(1000);
Task.Factory.StartNew(()=>
{
startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.ManagedThreadId,(A,B)=> B) ;
为(INT J = 0; J< 50; J ++)
Task.Factory.StartNew(()=> startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.ManagedThreadId, (A,b)=> b));

为(INT J = 0; J< 50; J ++)
{
Task.Factory.StartNew(( )=>
{
,而(tokenSource.Token.IsCancellationRequested)
{
如果(startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId!))Console.WriteLine(线程重复使用);
Thread.CurrentThread.Block(10);
如果(startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId))Console.WriteLine(螺纹重用);
}
},tokenSource.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default)
.ContinueWith(任务=>
{
WriteExceptions(task.Exception);
Console.WriteLine(-----------------------------);
},TaskContinuationOptions.OnlyOnFaulted );
}
Thread.CurrentThread.Block();
},tokenSource.Token,TaskCreationOptions.LongRunning,TaskScheduler.Default)
.ContinueWith(任务=>
{
WriteExceptions(task.Exception);
控制台.WriteLine(-----------------------------);
},TaskContinuationOptions.OnlyOnFaulted);
}

Console.Read();
}

私有静态无效WriteExceptions(异常前)
{
Console.WriteLine(ex.Message);
如果(!ex.InnerException = NULL)
WriteExceptions(ex.InnerException);
}
}
}


I am trying to create a new thread each time Task.Factory.StartNew is called. The question is how to run the code bellow without throwing the exception:

static void Main(string[] args)
        {
            int firstThreadId = 0;

            Task.Factory.StartNew(() => firstThreadId = Thread.CurrentThread.ManagedThreadId);

            for (int i = 0; i < 100; i++)
            {
                Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Thread.Sleep(1000);
                        if (firstThreadId == Thread.CurrentThread.ManagedThreadId)
                            throw new Exception("The first thread is reused.");
                    }
                });
            }
            Console.Read();
        }

EDIT: the new code if you comment the first for statement there is no problem. But if you have it, WOW, the message "Thread reused" is written to the console. Can you explain that because I am really confused.

static void Main(string[] args)
        {
            ConcurrentDictionary<int, int> startedThreads = new ConcurrentDictionary<int, int>();

            for (int i = 0; i < 10; i++)
            {
                Task.Factory.StartNew(() =>
                {
                    Task.Factory.StartNew(() =>
                    {
                        startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b);
                    }, TaskCreationOptions.LongRunning);

                    for (int j = 0; j < 100; j++)
                    {
                        Task.Factory.StartNew(() =>
                        {
                            while (true)
                            {
                                Thread.Sleep(10);
                                if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId))
                                    Console.WriteLine("Thread reused");
                            }
                        }, TaskCreationOptions.LongRunning);
                    }
                });
            }

            Console.Read();
        }

解决方案

Hello and thank you all for the answers. You all got +1. All suggested solution did not work for my case. The problem is that when you sleep a thread it will be reused at some point of time. The people above suggested:

  • using LongRunning => This will not work if you have nested/child tasks
  • custom task scheduler => I tried to write my own and also tried this ThreadPerTaskScheduler which also di not work.
  • using pure threads => Still failing...

My solution

I don't like it but it works. Basically I block the thread so it cannot be reused. Bellow are the extension methods and a working example. Again, thank you.

https://gist.github.com/4150635

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication
{
    public static class ThreadExtensions
    {
        /// <summary>
        /// Blocks the current thread for a period of time so that the thread cannot be reused by the threadpool.
        /// </summary>
        public static void Block(this Thread thread, int millisecondsTimeout)
        {
            new WakeSleepClass(millisecondsTimeout).SleepThread();
        }

        /// <summary>
        /// Blocks the current thread so that the thread cannot be reused by the threadpool.
        /// </summary>
        public static void Block(this Thread thread)
        {
            new WakeSleepClass().SleepThread();
        }

        /// <summary>
        /// Blocks the current thread for a period of time so that the thread cannot be reused by the threadpool.
        /// </summary>
        public static void Block(this Thread thread, TimeSpan timeout)
        {
            new WakeSleepClass(timeout).SleepThread();
        }

        class WakeSleepClass
        {
            bool locked = true;
            readonly TimerDisposer timerDisposer = new TimerDisposer();

            public WakeSleepClass(int sleepTime)
            {
                var timer = new Timer(WakeThread, timerDisposer, sleepTime, sleepTime);
                timerDisposer.InternalTimer = timer;
            }

            public WakeSleepClass(TimeSpan sleepTime)
            {
                var timer = new Timer(WakeThread, timerDisposer, sleepTime, sleepTime);
                timerDisposer.InternalTimer = timer;
            }

            public WakeSleepClass()
            {
                var timer = new Timer(WakeThread, timerDisposer, Timeout.Infinite, Timeout.Infinite);
                timerDisposer.InternalTimer = timer;
            }

            public void SleepThread()
            {
                while (locked)
                    lock (timerDisposer) Monitor.Wait(timerDisposer);
                locked = true;
            }

            public void WakeThread(object key)
            {
                locked = false;
                lock (key) Monitor.Pulse(key);
                ((TimerDisposer)key).InternalTimer.Dispose();
            }

            class TimerDisposer
            {
                public Timer InternalTimer { get; set; }
            }
        }
    }

    class Program
    {
        private static readonly Queue<CancellationTokenSource> tokenSourceQueue = new Queue<CancellationTokenSource>();
        static void Main(string[] args)
        {
            CancellationTokenSource tokenSource = new CancellationTokenSource();
            tokenSourceQueue.Enqueue(tokenSource);

            ConcurrentDictionary<int, int> startedThreads = new ConcurrentDictionary<int, int>();
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(1000);
                Task.Factory.StartNew(() =>
                {
                    startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b);
                    for (int j = 0; j < 50; j++)
                        Task.Factory.StartNew(() => startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b));

                    for (int j = 0; j < 50; j++)
                    {
                        Task.Factory.StartNew(() =>
                        {
                            while (!tokenSource.Token.IsCancellationRequested)
                            {
                                if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused");
                                Thread.CurrentThread.Block(10);
                                if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused");
                            }
                        }, tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                        .ContinueWith(task =>
                        {
                            WriteExceptions(task.Exception);
                            Console.WriteLine("-----------------------------");
                        }, TaskContinuationOptions.OnlyOnFaulted);
                    }
                    Thread.CurrentThread.Block();
                }, tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
                .ContinueWith(task =>
                {
                    WriteExceptions(task.Exception);
                    Console.WriteLine("-----------------------------");
                }, TaskContinuationOptions.OnlyOnFaulted);
            }

            Console.Read();
        }

        private static void WriteExceptions(Exception ex)
        {
            Console.WriteLine(ex.Message);
            if (ex.InnerException != null)
                WriteExceptions(ex.InnerException);
        }
    }
}

这篇关于是否有可能总是强制使用任务一个新线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆