Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
非Win Form C#应用程序中的同步事件处理程序线程执行_C#_Multithreading_Asynchronous_Event Handling - Fatal编程技术网

非Win Form C#应用程序中的同步事件处理程序线程执行

非Win Form C#应用程序中的同步事件处理程序线程执行,c#,multithreading,asynchronous,event-handling,C#,Multithreading,Asynchronous,Event Handling,我正在一个接一个地运行大量时间\CPU密集型进程(时间昂贵型)。主线程(A)异步启动另一个线程(B)中耗时较长的进程,并变为非活动状态。完成时,线程B同步启动调用方的完成处理程序,并在线程B中启动下一个昂贵的进程。创建一个新线程(C),但在启动C后,B完成。因此,对于n个进程,创建了n个线程,并且大多数情况下,它们并不共存 人们可能希望它以线性单线程的方式实现,但时间昂贵的是由第三方实现的,当它运行时,它使用所有系统内核并运行数小时 //This will run as console app

我正在一个接一个地运行大量时间\CPU密集型进程(时间昂贵型)。主线程(A)异步启动另一个线程(B)中耗时较长的进程,并变为非活动状态。完成时,线程B同步启动调用方的完成处理程序,并在线程B中启动下一个昂贵的进程。创建一个新线程(C),但在启动C后,B完成。因此,对于n个进程,创建了n个线程,并且大多数情况下,它们并不共存

人们可能希望它以线性单线程的方式实现,但时间昂贵的是由第三方实现的,当它运行时,它使用所有系统内核并运行数小时

//This will run as console app 
class Program
{
    static void Main(string[] args)
    {
        new Program().StartJobs();
    }

    void StartJobs()
    {
        Main mainJob = new Main();
        mainJob.MainCompletionEvent += 
                     new Action<object, EventArgs>(mainJob_MainCompletionEvent);
        mainJob.Start();
    }

    void mainJob_MainCompletionEvent(object sender, EventArgs e)
    {
        //if(success) Environment.Exit(0);
    }

}

class Main
{
    int processCounter = 0;
    public event Action<object, EventArgs> MainCompletionEvent;
    public void Start()
    {
        //...do other important tasks here...
        processCounter++;
        TimeExpensive te = new TimeExpensive();
        te.CompletionEvent += new Action(TimeExpensive_CompletionHandler);
        Thread aThread = new Thread(te.Run);
        aThread.IsBackground = false;
        aThread.Name = "TimeExpensive Thread: " + processCounter;
        aThread.Start();
    }

    void TimeExpensive_CompletionHandler()
    {
        Console.WriteLine("current Thread Name: " + Thread.CurrentThread.Name);
        //Start another Process In Background if
        if (processCounter < 5)
        {
            Start();
        }
        else
        {
            Console.ReadKey();
            if (JobCompletionEvent != null)
                JobCompletionEvent(this, new EventArgs());
        }
    }
}

class TimeExpensive
{
    public event Action CompletionEvent;

    public void Run()
    {
        //doing time expensive task
        //...

        //when finish Notify completion Handler...
        if (CompletionEvent != null)
        {
            CompletionEvent();
        }
    }
}

//Output
current Thread Name: TimeExpensive Thread: 1
current Thread Name: TimeExpensive Thread: 2
current Thread Name: TimeExpensive Thread: 3
current Thread Name: TimeExpensive Thread: 4
current Thread Name: TimeExpensive Thread: 5
//这将作为控制台应用程序运行
班级计划
{
静态void Main(字符串[]参数)
{
新程序().StartJobs();
}
void StartJobs()
{
Main mainJob=新的Main();
mainJob.MainCompletionEvent+=
新操作(mainJob\u MainCompletionEvent);
mainJob.Start();
}
void mainJob\u MainCompletionEvent(对象发送方,事件参数e)
{
//if(成功)环境。退出(0);
}
}
班长
{
int processCounter=0;
公共事件行动维护完成事件;
公开作废开始()
{
//…在此执行其他重要任务。。。
processCounter++;
时间昂贵te=新的时间昂贵();
te.CompletionEvent+=新操作(timeexposite\u CompletionHandler);
Thread aThread=新线程(te.Run);
aThread.IsBackground=false;
aThread.Name=“时间昂贵线程:”+processCounter;
aThread.Start();
}
void timer\u CompletionHandler()
{
Console.WriteLine(“当前线程名称:+Thread.CurrentThread.Name”);
//如果需要,请在后台启动另一个进程
if(进程计数器<5)
{
Start();
}
其他的
{
Console.ReadKey();
if(JobCompletionEvent!=null)
JobCompletionEvent(这是新的EventArgs());
}
}
}
上课时间昂贵
{
公共事件行动完成事件;
公开募捐
{
//做耗时的工作
//...
//当完成通知完成处理程序。。。
if(CompletionEvent!=null)
{
CompletionEvent();
}
}
}
//输出
当前线程名称:时间昂贵线程:1
当前线程名称:时间昂贵线程:2
当前线程名称:时间昂贵线程:3
当前线程名称:时间昂贵线程:4
当前线程名称:时间昂贵线程:5
上面的实现模仿了我描述的行为。困扰我的是事件处理程序一直同步运行,直到下一个线程启动,在这段时间内,它正在执行许多不是为它设计的任务

不确定这是否好,是否有一种方法可以在线程B的完成处理程序中返回到线程a?或者我最好使用另一个delegate.BeginInvoke启动事件处理程序执行

我希望用简单而安全的方法来做。非常感谢您的帮助

我读了很多帖子,但没有人能很好地处理这种情况

编辑 添加Static main以显示如何在控制台应用程序中启动此代码。请记住,还可以创建UI来启动“主”作业。它肯定会创建BackgroundWorker线程来创建mainJob对象并运行它。
谢谢

您遇到的问题是由于正确执行线程操作有多困难。我用演员为你的例子编码:

type Actor<'a> = MailboxProcessor<'a>

type SupMsg = WaitForDone of AsyncReplyChannel<string>
type ProgramState = RunNumber of int * Actor<WorkerMsg> option
and WorkerMsg = Begin of Id * AsyncReplyChannel<string>
and Id = int

let startComputation () = Actor.Start(fun inbox ->
  async { 
    let! Begin(id, chan) = inbox.Receive()
    printfn "Running Computation"
    do! Async.Sleep(20) // zZz
    chan.Reply(sprintf "'%i is done!'" id) })

let sup () = Actor.Start(fun inbox ->
  let rec loop state =
    async {
      match state with
      | RunNumber(_, None) -> return! loop <| RunNumber(1, Some(startComputation ()))
      | RunNumber(run, Some(active)) ->
        let! completed = active.PostAndAsyncReply(fun chan -> Begin(run, chan))
        printfn "sup observed: %s" completed
        let active' = Some(startComputation ())
        if run <> 5 then return! loop <| RunNumber(run + 1, active')
        else return! isDone () }
  and isDone () =
    async {
      let! WaitForDone(chan) = inbox.Receive()
      return chan.Reply("all done") }

  loop <| RunNumber(0, None))

[<EntryPoint>]
let main args =
  printfn "%s" <| (sup ()).PostAndReply(fun chan -> WaitForDone(chan))
  0
如您所见,跨线程通信变得轻而易举。如果您的库是第三方库,那么很容易用对库的调用替换
Async.Sleep(20)

在线程B的完成处理程序中,有没有办法返回到线程a

不,您没有适当的管道来封送从一个线程到另一个线程的调用。这种管道是由GUI应用程序的主线程提供的。出于必要,用户界面基本上是线程不安全的。支持这种封送的UI线程有几个实现细节。它的行为就像线程模型的典型实现中的使用者

这需要线程安全队列和读取队列的使用者中的循环。您可以将其识别为Windows GUI应用程序中的消息队列。使用调用GetMessage的消息循环来读取通知并对其执行操作。封送调用现在很简单,只需将消息发布到消息队列中,UI线程就会读取消息并执行请求。过帐由Winforms的Control.BeginInvoke和WPF的Dispatcher.BeginInvoke实现


您当然可以自己实现这个同步机制。NET 4 BlockingCollection类使它变得简单。但是请记住,您必须从根本上改变线程A的执行方式。保持对发送到队列的请求的响应非常重要。像BackgroundWorker这样的类试图解决的问题。请记住,GUI消息循环的存在是因为它是必需的,UI不是线程安全的。控制台应用程序(通常)没有相同的负担,控制台是线程安全的。

它使用所有系统内核。它可能以一种不寻常的方式实现,但它似乎做了很多有用的工作?我不认为在OnCommpleteion处理程序中工作是必要的邪恶-这是工作,只是另一个函数调用。我不明白使用不同的线程为A,B,C无论如何。为什么不能按顺序运行呢?无论如何,如果有必要进行任何更改,我会为A、B、C转储线程并提交池任务。使用多核是最好的选择,尤其是当您有专用服务器时。第三方实现了时间昂贵的进程以异步运行。我只使用了一个dll。在另一个线程中运行timeexplicate的另一个优点是在timeexplicate上间接取消异步调用。流产
> main();;
Running Computation
sup observed: '1 is done!'
Running Computation
sup observed: '2 is done!'
Running Computation
sup observed: '3 is done!'
Running Computation
sup observed: '4 is done!'
Running Computation
sup observed: '5 is done!'
all done
val it : int = 0