关于“无法访问已释放的对象”,老问题,不知道如何解决

bcc222 2011-03-11 12:14:08
最近做程序,采用定时器加委托方式对进行控制程序如下:




System.DateTime oldtime=new DateTime();
delegate void SetTextCallback(string strTime);//定义托管函数
System.Timers.Timer t = new System.Timers.Timer(100);//实例化Timer类
bool closeFlag;
public Form1()
{
InitializeComponent();
}
private void timeClass_Click(object sender, EventArgs e)
{
t.Elapsed+= new System.Timers.ElapsedEventHandler(theout);//到达时间的时候执行事件;
t.AutoReset = true;//设置是执行一次(false)还是一直执行(true);
t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件;

}
public void theout(object source, System.Timers.ElapsedEventArgs e) //定时器调用
{

System.DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
string ss = (currentTime - oldtime).TotalMilliseconds.ToString();
oldtime = currentTime;
AddText(ss);
}

void AddText(string strTime)
{
//在此处使用过:this.isDisposed和this.Disposing进行判定,无法解决
if (this.listView1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(AddText);
this.Invoke(d, new object[] { strTime });//此处出现,无法释放问题
}
else
{
string[] str = { listView1.Items.Count.ToString(), "测试", strTime };
ListViewItem item = new ListViewItem(str);
listView1.Items.Add(item);
}
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{

t.Close();//这个地方如果增加一个关闭t.close的话也不行,定时器整个form关闭前没有被关闭!
Thread.Sleep(500);
}




程序的主要思想在定时器的状态下,向listview表中写数据,现在问题是,如果程序关闭的时候,定时器不会关闭,这个时候往list中写数据,会提示From已被释放。

在网上也看了很多类似的帖子,主要方法如下:
1、使用this.isDisposed,this.Disposing进行判定
2、在退出的时候增加一个判定的变量,如quitFlag
3、退出的时候增加一个sleep也不行,总是感觉我的from被关闭的时候,定时器还没有被关闭
以上方法都做过测试了,都不行!

以上还有没有更好的方法,目前测试要是能在from关闭前!!完全!!关掉定时器,程序退出就没有问题!
不要给我说用try...catch,这个根本就不是一个解决方法,说Try...catch的不给分,吼吼。

...全文
4463 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
bcc222 2012-08-19
  • 打赏
  • 举报
回复
谢谢,这么长时间了,还有人回复,谢谢!
米娅爱吃糖 2012-08-16
  • 打赏
  • 举报
回复
是不是不同线程造成的。

下面的来自msdn

在一个线程调用 Stop 方法或将 Enabled 属性设置为 false 的同时,可在另一个线程上运行事件处理方法。这可能导致在计时器停止之后引发 Elapsed 事件。Stop 方法的示例代码演示了一种避免此争用条件的方法。

Timer.Stop 方法
http://msdn.microsoft.com/zh-cn/library/system.timers.timer.stop(v=vs.80)
yang1216 2011-05-04
  • 打赏
  • 举报
回复
LZ,问题解决了吗?
bcc222 2011-03-12
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 yyz985 的回复:]
关注,用楼主的代码试了一下,没有碰到问题
[/Quote]
应该是有问题的,退出的时候出现问题,最近继续在研究多线程编程,回头等另外开帖子说明吧!
shaofei830927 2011-03-11
  • 打赏
  • 举报
回复
你这种写法是不对的
AddText 方法中
SetTextCallback d = new SetTextCallback(AddText);
this.Invoke(d。。。

也就意味着 this.listView1.InvokeRequired==true时
之前所调用的所有的 AddText方法体(包括其中的 SetTextCallback)都不会释放掉
也就是说 如果this.listView1.InvokeRequired一直保持为true状态的话
会使无数个AddText 不能释放 最后形成无限递归

而 while 不同 它占用的资源不会因为 循环的次数不同 而 变化
建议你用另起线程循环 而不是 另起线程递归
(t.Elapsed+= new System.Timers.ElapsedEventHandler(theout)实际上是另起线程执行)

以上致使 关闭窗口后无法释放掉该方法体 该方法体还需要form窗体资源
所以会出现"访问已经释放的资源"异常
你把 Invoke 改为BeginInvoke 其实资源还是没有释放掉
但是由于非主线程的异常 不会为主线程捕获到 所以你没有获得异常信息

所以 要做在某一段时间内 无限执行的东西 用 while 不要用 递归
bcc222 2011-03-11
  • 打赏
  • 举报
回复
再进一步咨询一下,为什么我在Form1_FormClosing中已经关闭了定时器了,定时器还在运行中呢?
bcc222 2011-03-11
  • 打赏
  • 举报
回复
太牛了@!
bdmh 2011-03-11
  • 打赏
  • 举报
回复 2
改成
this.BeginInvoke(d, new object[] { strTime })
yyz985 2011-03-11
  • 打赏
  • 举报
回复
关注,用楼主的代码试了一下,没有碰到问题
bcc222 2011-03-11
  • 打赏
  • 举报
回复
自己又用进程做了一下

while (true)
{
s++;

System.DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
string ss = (currentTime - oldtime).TotalMilliseconds.ToString();
oldtime = currentTime;

if (this.InvokeRequired)
{
SetTextCallback d =AddText;//这个地方直接赋值,不用new,也就不产生递归了 object kkk = this.BeginInvoke(d, new object[] { ss.ToString() }); ;

}
Thread.Sleep((int)ms);

}





不过退出的时候如果不注意,用Invoke还是会报错,估计应该是线程与主进程之间退出问题,能不能请教一下如何在主进程结束前明确将子进程完全退出掉?
bcc222 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 yalan 的回复:]
引用 13 楼 bcc222 的回复:
引用 12 楼 soulhugh 的回复:
把你的线程设置为后台线程

这个用定时器做的,不知道怎么设置为后台进程呢!


改成多线程吧,多线程可以设置为后台进程。计时器应该不行
[/Quote]

呵呵,我的初衷不是要用什么东西,如果用form的时间控件更容易,都不用委托,我正好是在学习状态中,不太想绕开!有点驴脾气了,呵呵!
bcc222 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 jinkuang45 的回复:]
一步到位

System.Environment.Exit(0);
[/Quote]
这种做法挺猛,也能用,不过感觉不太好!


*******************************************************
我重新把程序修改了一下:

public void theout(object source, System.Timers.ElapsedEventArgs e)
{

System.DateTime currentTime = new DateTime();
currentTime = DateTime.Now;
string ss = (currentTime - oldtime).TotalMilliseconds.ToString();
oldtime = currentTime;
if (this.listView1.InvokeRequired)//这个地方从AddText函数中移出来了
{
SetTextCallback d = new SetTextCallback(AddText);
this.Invoke(d, new object[] { ss });//此处出现,无法释放问题
}
else
{
AddText(ss);
}

}
bool AddText(string strTime)
{
string[] str = { listView1.Items.Count.ToString(), "测试", strTime };
ListViewItem item = new ListViewItem(str);
listView1.Items.Add(item);
item.EnsureVisible();//设置当前记录可见
return true;

}


我把这句: if (this.listView1.InvokeRequired)//这个地方从AddText函数中移出来了

流程的话就是,每100ms就执行一次theout()函数,如果判定InvokeRequired的话,我就用委托扔到消息队列里面去(不知道这样的说法对不对!),否则的话我就直接进行显示!

这样应该就不是递归了!

可是这样在退出的时候还是不行!



yalan 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 bcc222 的回复:]
引用 12 楼 soulhugh 的回复:
把你的线程设置为后台线程

这个用定时器做的,不知道怎么设置为后台进程呢!
[/Quote]

改成多线程吧,多线程可以设置为后台进程。计时器应该不行
bcc222 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 soulhugh 的回复:]
把你的线程设置为后台线程
[/Quote]
这个用定时器做的,不知道怎么设置为后台进程呢!
soulhugh 2011-03-11
  • 打赏
  • 举报
回复
把你的线程设置为后台线程
冰川711 2011-03-11
  • 打赏
  • 举报
回复
一步到位

System.Environment.Exit(0);
bcc222 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 freetd 的回复:]
注意是先停掉timer不是释放

引用楼主 bcc222 的回复:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{

t.Close();//这个地方如果增加一个关闭t.close的话也不行,定时器整个form关闭前没有被关闭!
Thread.Sleep(500);
}
[/Quote]


用t.stop()也不行
bcc222 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 freetd 的回复:]
在FormClosing事件里写上停掉timer不是更好
[/Quote]
现在是在form中停不掉timer!应该是递归的问题!

可是我本意并没有想写成递归啊!
freetd 2011-03-11
  • 打赏
  • 举报
回复
注意是先停掉timer不是释放
[Quote=引用楼主 bcc222 的回复:]
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{

t.Close();//这个地方如果增加一个关闭t.close的话也不行,定时器整个form关闭前没有被关闭!
Thread.Sleep(500);
}

[/Quote]
bcc222 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 shaofei830927 的回复:]
你这种写法是不对的
AddText 方法中
SetTextCallback d = new SetTextCallback(AddText);
this.Invoke(d。。。

也就意味着 this.listView1.InvokeRequired==true时
之前所调用的所有的 AddText方法体(包括其中的 SetTextCallback)都不会释放掉
也就是说 如……
[/Quote]


我这个地方开了一个递归了 SetTextCallback d = new SetTextCallback(AddText);
请教一下,这个程序要修改的话如何修改呢?什么时候InvokeRequired才为false?
加载更多回复(2)

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧