Wil*_*lem 31 .net c# multithreading thread-safety multitasking
我正在寻找正确的方法/结构来创建一个循环Thread/Task...
原因是,我需要每15秒检查一次数据库以获取报告请求.
这是我到目前为止所尝试的,但我得到OutOfMemoryException:
private void ViewBase_Loaded(object sender, RoutedEventArgs e)
{
//On my main view loaded start thread to check report requests.
Task.Factory.StartNew(() => CreateAndStartReportRequestTask());
}
private void CreateAndStartReportRequestTask()
{
bool noRequest = false;
do
{
//Starting thread to Check Report Requests And Generate Reports
//Also need the ability to Wait/Sleep when there are noRequest.
reportRequestTask = Task.Factory.StartNew(() => noRequest = CheckReportRequestsAndGenerateReports());
if (noRequest)
{
//Sleep 15sec
reportRequestTask.Wait(15000);
reportRequestTask = null;
}
else
{
if (reportRequestTask.IsCompleted)
{
reportRequestTask = null;
}
else
{
//Don't want the loop to continue until the first request is done
//Reason for this is, losts of new threads being create in CheckReportRequestsAndGenerateReports()
//Looping until first request is done.
do
{
} while (!reportRequestTask.IsCompleted);
reportRequestTask = null;
}
}
} while (true);
}
private bool CheckReportRequestsAndGenerateReports()
{
var possibleReportRequest = //Some linq query to check for new requests
if (possibleReportRequest != null)
{
//Processing report here - lots of new threads/task in here as well
return false;
}
else
{
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
这是正确的方式还是完全关闭?
编辑:
最重要的是,我的用户界面仍然必须响应!
Rog*_*mbe 58
像这样的东西会起作用:
var cancellationTokenSource = new CancellationTokenSource();
var task = Repeat.Interval(
TimeSpan.FromSeconds(15),
() => CheckDatabaseForNewReports(), cancellationTokenSource.Token);
Run Code Online (Sandbox Code Playgroud)
这个Repeat类看起来像这样:
internal static class Repeat
{
public static Task Interval(
TimeSpan pollInterval,
Action action,
CancellationToken token)
{
// We don't use Observable.Interval:
// If we block, the values start bunching up behind each other.
return Task.Factory.StartNew(
() =>
{
for (;;)
{
if (token.WaitCancellationRequested(pollInterval))
break;
action();
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
}
static class CancellationTokenExtensions
{
public static bool WaitCancellationRequested(
this CancellationToken token,
TimeSpan timeout)
{
return token.WaitHandle.WaitOne(timeout);
}
}
Run Code Online (Sandbox Code Playgroud)
Jam*_*are 21
听起来你想要这样的东西.如果我误解了你的意图,请纠正我...
首先,在启动时,将其设置为一个长时间运行的任务,这样它就不会消耗线程池中的线程,而是创建一个新线程...
private void ViewBase_Loaded(object sender, RoutedEventArgs e)
{
// store this references as a private member, call Cancel() on it if UI wants to stop
_cancelationTokenSource = new CancellationTokenSource();
new Task(() => CreateAndStartReportRequestTask(), _cancelationTokenSource.Token, TaskCreationOptions.LongRunning).Start();
}
Run Code Online (Sandbox Code Playgroud)
然后,在您的报告中观看线程,循环直到IsCancelRequested已设置.如果没有工作,只需等待取消令牌15秒(这种方式如果取消将更快唤醒).
private bool CheckReportRequestsAndGenerateReports()
{
while (!_cancellationTokenSource.Token.IsCancelRequested)
{
var possibleReportRequest = //Some linq query
var reportRequestTask = Task.Factory.StartNew(() => noRequest = CheckReportRequestsAndGenerateReports(), _cancellationTokenSource.Token);
if (noRequest)
{
// it looks like if no request, you want to sleep 15 seconds, right?
// so we'll wait to see if cancelled in next 15 seconds.
_cancellationTokenSource.Token.WaitHandle.WaitOne(15000);
}
else
{
// otherwise, you just want to wait till the task is completed, right?
reportRequestTask.Wait(_cancellationTokenSource.Token);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我也要小心让你的任务开始更多的任务.我有一种感觉,你在旋转太多,你消耗了太多的资源.我认为你的程序失败的主要原因是你有:
if (noRequest)
{
reportRequestTask.Wait(15000);
reportRequestTask = null;
}
Run Code Online (Sandbox Code Playgroud)
这将立即返回而不是等待15秒,因为此时线程已经完成.将它切换到取消令牌(或者a Thread.Sleep(),但是你不能轻易地中止它)将为你提供所需的处理等待.
希望这会有所帮助,请告诉我,如果我对我的假设不以为然.
我从@ Roger的答案开始做了一个解决方案.(我的一个朋友也对此给出了很好的建议)...我在这里复制它我觉得它可能有用:
/// <summary>
/// Recurrent Cancellable Task
/// </summary>
public static class RecurrentCancellableTask
{
/// <summary>
/// Starts a new task in a recurrent manner repeating it according to the polling interval.
/// Whoever use this method should protect himself by surrounding critical code in the task
/// in a Try-Catch block.
/// </summary>
/// <param name="action">The action.</param>
/// <param name="pollInterval">The poll interval.</param>
/// <param name="token">The token.</param>
/// <param name="taskCreationOptions">The task creation options</param>
public static void StartNew(Action action,
TimeSpan pollInterval,
CancellationToken token,
TaskCreationOptions taskCreationOptions = TaskCreationOptions.None)
{
Task.Factory.StartNew(
() =>
{
do
{
try
{
action();
if (token.WaitHandle.WaitOne(pollInterval)) break;
}
catch
{
return;
}
}
while (true);
},
token,
taskCreationOptions,
TaskScheduler.Default);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
62497 次 |
| 最近记录: |