Asp.net 如何等待一个子线程结束

jmcooler 2020-11-05 03:04:28
我想在 Application_End() 中等待一个子线程安全结束。

在 IIS 中,当管理员 stop 网站时,我希望子线程保存数据,然后安全退出,之后网站才停止。

但是,我下面的代码,在 sbThread.Join() 时,.NET 将会在片刻等待之后,强行退出,根本不等我的后台背景线程保存数据。

结果,子线程仅仅保存了一半的数据,其余的则丢失了。

protected void Application_End( object sender, EventArgs e )
{
Thread workThread;
lock( dataStore.sbpSync )
{
workThread = dataStore.workThread;
dataStore.exiting = true;
dataStore.autoEvent.Set();
}
if( workThread != null )
workThread.Join();
}


就像我们在写桌面程序那样,程序退出之前,需要保存数据。 Asp.net 应该有这个机制吧?

...全文
2725 18 打赏 收藏 举报
写回复
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
andy0618 2020-11-10
用Task,可以看一下Task,Task是对thread进一步的封装
  • 打赏
  • 举报
回复
wanghui0380 2020-11-09
引用 14 楼 jmcooler 的回复:
已经解决了,只要在创建线程的时候,指定 IsBackground = false,设置线程为前台线程即可。 不是我拧巴,办法总是多种多样的,思路当然应该要开阔。 但就怕“为解决而解决”,只治标不治本,这是要命的. 有时候,没必要为 A 的问题引入 B,又为 B 的问题引入 C,这种简单的堆砌是要出问题的.
从博客园看的东西千万不要乱引用,也别当不作为的借口。 设计采用正交设计,解耦设计,隔离设计。相反你跟博客园们学的才是头痛医脚,到处攀扯的搞法。 就如16楼说的,本来他就和线程和iis没关系。不解耦,不隔离,还得说我用A,所以要线程,所以要前台。当你都是隔离的,这问题才是各做的各的。
  • 打赏
  • 举报
回复
syeerzy 2020-11-09
因为iis和windows服务都不应该长时间等待一个后台线程. 对于你这个场景, 建议你 1 单独使用一个进程来做这件事. 与iis是否重启无关. 2 使用事务机制. 最后那个执行一半的回滚.
  • 打赏
  • 举报
回复
qq_30412191 2020-11-09
stop的时候,肯定会有个关闭事件,或者关闭之前事件,不知道这样想对不对
  • 打赏
  • 举报
回复
jmcooler 2020-11-06
你们的回答很好,我确实对 msmq 不熟悉,知道有这个东西,但不知道干嘛用的。 我说,Web 服务器应该有机制来等待子线程安全退出,也是从理论上说的,它也应该如此。 至于蓝屏、掉电导致数据丢失,这是极端情况,你不能拿来与正常情况类比。 如果按照你们这样的思维,那么每个 Windows 桌面程序都可以不等待子线程结束,而强行退出,连这个机制都不用提供,主线程直接跨嚓退了。 类似于 msmq 的持久化队列,只是一种补救措施,是没办法的办法。 这是我的理解和意见。 多谢各位回复和探讨
  • 打赏
  • 举报
回复
jmcooler 2020-11-06
已经解决了,只要在创建线程的时候,指定 IsBackground = false,设置线程为前台线程即可。 不是我拧巴,办法总是多种多样的,思路当然应该要开阔。 但就怕“为解决而解决”,只治标不治本,这是要命的. 有时候,没必要为 A 的问题引入 B,又为 B 的问题引入 C,这种简单的堆砌是要出问题的.
  • 打赏
  • 举报
回复
wanghui0380 2020-11-06
至于你一定要纠结,啥子线程结束。 那就给阻塞信号,
ManualResetEventSlim x = new ManualResetEventSlim(true);
         
            Thread t = new Thread(new ThreadStart(() =>
            {
              
               
                for (int i = 0; i < 100; i++)
                {
                    Trace.WriteLine(i);
                }
                x.Set();
                
            }));
            t.Start();
            x.Reset();
            x.Wait();
            Console.Write($"t 结束了");
  • 打赏
  • 举报
回复
wanghui0380 2020-11-06
所以不就是应该用另一个程序收?有哪个web 服务关闭时要先等待线程结束的你说一下? 没人说用mq就一定是另一个程序。你想web玩一样玩,你可以Application_End,自然也可以Application_Start 接上消息 不用纠结,玩qt的还用命名管道和油槽进行多窗体控制呢,谁能说这是错的。相反这也许是跟接近正确的方案。
  • 打赏
  • 举报
回复
wanghui0380 2020-11-06
引用 8 楼 lorimoon 的回复:
[quote=引用 4 楼 wanghui0380的回复:]额,你的意思是,你不是立刻发的,是有个队列发 这个队列的是内存化的,应用程序池重启他就掉了,所以需要在重启前持久化 如果我理解的没错,那么我们说,你需要一个自己就能持久化的队列,而不是自己在重启前弄(最差的情况是蓝屏,掉电,这你拦不住把,所以需要他自己就能持久) so,愿意接受新东西,非微软的东西可以用rabbitmq,activmq,不愿意非微软的方案就请在服务器端开启msmq微软消息队列 这些都是自动持久化的
我建议是直接连接数据库写收日志,数据库数据安全不比你这些安全得多?一个小网站用不上这些。[/quote] 有时候不要那么拧巴。iis,msmql,msmq都是微软同时代同等级的产品,太过拧巴就不好了。自己想把,微软干嘛在20年前就同时提供你3个东西 回答是他们的设计目标和方向不同。iis提供web,mssql提供存储,msmq提供消息(支持持久化和优先级) 数据库写日志??写日志谁通知你有新东西了?跟博客园学定时器一遍一遍刷,然后比对么?
  • 打赏
  • 举报
回复
程序都结束了,没必要用线程,写成同步的就行了。
  • 打赏
  • 举报
回复
lorimoon 2020-11-06
引用 4 楼 wanghui0380的回复:
额,你的意思是,你不是立刻发的,是有个队列发 这个队列的是内存化的,应用程序池重启他就掉了,所以需要在重启前持久化 如果我理解的没错,那么我们说,你需要一个自己就能持久化的队列,而不是自己在重启前弄(最差的情况是蓝屏,掉电,这你拦不住把,所以需要他自己就能持久) so,愿意接受新东西,非微软的东西可以用rabbitmq,activmq,不愿意非微软的方案就请在服务器端开启msmq微软消息队列 这些都是自动持久化的
我建议是直接连接数据库写收日志,数据库数据安全不比你这些安全得多?一个小网站用不上这些。
  • 打赏
  • 举报
回复
lorimoon 2020-11-06
引用 5 楼 jmcooler的回复:
楼上,你这个说法不对,当然,感谢你的回复。 无论是哪种 Web 服务器,它在停止时,肯定是先关闭 80 端口的监听,然后等待子线程安全退出。 如果不是这样,服务器强制退出,那么你的任何子线程都会丢失数据,无论你是写日志,还是写数据库。 我刚收到一个数据,你跨嚓就退出了,我怎么做都没用。 也就可以下结论说,Web 服务器根本不支持子线程,如果你要用子线程,就必然接受“丢失数据”。 我现在的思路是,用 Task 来代替 Thread,让“发回校验”的业务在系统的线程池执行,看 IIS 是不是可以让它安全退出
所以不就是应该用另一个程序收?有哪个web 服务关闭时要先等待线程结束的你说一下?
  • 打赏
  • 举报
回复
wanghui0380 2020-11-05
我们并不想讨论什么应用程序池就应该等着你结束,他才结束,因为你要一辈子不结束,他那倒是麻烦事 比如window关机就会可能弹出一个框告诉你,xx程序打死不结束,他阻止关机 我们只是告诉你,请开启msmq看看结果,你会发现世界不一样的(虽然msmq也不是新东西,几乎跟mssql一样古老,但是你看不见他,也许一辈子都看不见)
  • 打赏
  • 举报
回复
jmcooler 2020-11-05
楼上,你这个说法不对,当然,感谢你的回复。 无论是哪种 Web 服务器,它在停止时,肯定是先关闭 80 端口的监听,然后等待子线程安全退出。 如果不是这样,服务器强制退出,那么你的任何子线程都会丢失数据,无论你是写日志,还是写数据库。 我刚收到一个数据,你跨嚓就退出了,我怎么做都没用。 也就可以下结论说,Web 服务器根本不支持子线程,如果你要用子线程,就必然接受“丢失数据”。 我现在的思路是,用 Task 来代替 Thread,让“发回校验”的业务在系统的线程池执行,看 IIS 是不是可以让它安全退出
  • 打赏
  • 举报
回复
wanghui0380 2020-11-05
额,你的意思是,你不是立刻发的,是有个队列发 这个队列的是内存化的,应用程序池重启他就掉了,所以需要在重启前持久化 如果我理解的没错,那么我们说,你需要一个自己就能持久化的队列,而不是自己在重启前弄(最差的情况是蓝屏,掉电,这你拦不住把,所以需要他自己就能持久) so,愿意接受新东西,非微软的东西可以用rabbitmq,activmq,不愿意非微软的方案就请在服务器端开启msmq微软消息队列 这些都是自动持久化的
  • 打赏
  • 举报
回复
lorimoon 2020-11-05
大哥既然你的数据是这么重要的话,你应该是所有操作都应该以你的格式绕过操作系统缓存写成日志记录,一个程序专门接收这些数据。然后发送的又是另一个程序又是写日志。第三程序是将接收发送的日志定时归档。什么都是IIS 做成何体系。不想烦写数据库也可以。
  • 打赏
  • 举报
回复
jmcooler 2020-11-05
难道,Asp.net 就没有机制来保证 子线程数据 的安全,说退出就强制退出了? 那我刚收到“事件”,网站就退出了,那不是很扯蛋?
  • 打赏
  • 举报
回复
jmcooler 2020-11-05
顺便说一下,我这个子线程的场景: 我正在集成 Paypal 支付系统,Paypal 会向我的网站发出各种支付进度、失败、原因、退款、争议的事件。 我收到这些事件后,得将它们原样发回,以校验这些事件的真实性,确保它们不是第三方伪造的。 于是,我启用一个后台线程,将收到的事件排队,发回给 Paypal,如因网络原因发送失败,将重新发送(最多 12 次,且限时 2 天),直到发送成功为止。 当站长 stop 网站时,我希望这些“事件数据”能保存,下次网站重启时,接着发。
  • 打赏
  • 举报
回复
相关推荐
发帖
.NET社区

6.0w+

社区成员

.NET技术交流专区
社区管理员
  • ASP.NET
  • R小R
  • 喵叔哟
加入社区
帖子事件
创建了帖子
2020-11-05 03:04
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。