public class ServerThread
{
const int DELAY_TIMES = 1000 * 45 ; private ServerThread()
{
}
/// <summary>
/// 获取或设置是否中断线程
/// </summary>
bool CanExit = false ;
Thread thread;
public void Start()
{
thread = new Thread(new ThreadStart(CheckProcess)); thread.Name = "Check News" ;
thread.Start();
thread.Join();
Error.Log("后台线程于" + DateTime.Now.ToString() + " 启动! 状态为:" + thread.ThreadState.ToString());
} public void Stop()
{
CanExit = true ;
Error.Log("后台线程于" + DateTime.Now.ToString() + " 停止! ");
} #region 线程运行主体方法
/// <summary>
/// 执行检测
/// </summary>
void CheckProcess()
{
while(!CanExit)
{
lock(this)
{
//在线用户检查
CheckOnLine() ;
}
Thread.Sleep(DELAY_TIMES);
}
thread.Abort();
}
#endregion
#region 在线用户检查
void CheckOnLine()
{
foreach(DefaultUser oUser in UserOnLine.Items)
{
if(oUser.LastAccessTime.AddSeconds(50) < DateTime.Now)
{
UserOnLine.Remove(oUser.ID);
}
}
} #endregion
{
const int DELAY_TIMES = 1000 * 45 ; private ServerThread()
{
}
/// <summary>
/// 获取或设置是否中断线程
/// </summary>
bool CanExit = false ;
Thread thread;
public void Start()
{
thread = new Thread(new ThreadStart(CheckProcess)); thread.Name = "Check News" ;
thread.Start();
thread.Join();
Error.Log("后台线程于" + DateTime.Now.ToString() + " 启动! 状态为:" + thread.ThreadState.ToString());
} public void Stop()
{
CanExit = true ;
Error.Log("后台线程于" + DateTime.Now.ToString() + " 停止! ");
} #region 线程运行主体方法
/// <summary>
/// 执行检测
/// </summary>
void CheckProcess()
{
while(!CanExit)
{
lock(this)
{
//在线用户检查
CheckOnLine() ;
}
Thread.Sleep(DELAY_TIMES);
}
thread.Abort();
}
#endregion
#region 在线用户检查
void CheckOnLine()
{
foreach(DefaultUser oUser in UserOnLine.Items)
{
if(oUser.LastAccessTime.AddSeconds(50) < DateTime.Now)
{
UserOnLine.Remove(oUser.ID);
}
}
} #endregion
如果是,你的这个对象的实例在哪里定义的?如果是在某个页面里,实例可能被释放了,你试试把它写成静态的实例
static ServerThread _Thread ;
public static ServerThread Instance
{
get
{
if(_Thread == null)
_Thread = new ServerThread() ;
return _Thread ;
}
}在Global.asax中:
protected void Application_Start(Object sender, EventArgs e)
{
ServerThread.Instance.Start();
}
我是初学者,有时说的过于浅溥,
2、JOIN() 只是同步线程,用于后面的代码可以获取线程的正确状态。
应该不是以上问题。 不过, 还是谢谢你们。 :)
确实如此,很是奇怪我现在的项目里有类似的功能,但是我的做法与你有一点不同:
1、在Global里面有一个静态的实例处理功能
2、在某一个页面点击按钮后new一个线程来启动该实例的某个方法我想了半天,实际上和你的几乎没有差别我要下班了,回去好好想想,明天再来讨论
thread.Start();
thread.Join();
Error.Log("后台线程于" + DateTime.Now.ToString() + " 启动! 状态为:" + thread.ThreadState.ToString());
^^^^^^^^^^^^^^^^^^^^^^^^^---- 这句话存在线程竞争CPU的不确定性!!!!!
请问你在线程方法主体内做了哪些操作?
我刚刚测试了一下, 我在线程方法中写了一个循环, 其他没有任何操作, 此时线程是正常运行的。
但是,一旦在循环中加入任何操作,如进行系统IO操作, 线程即刻自动中止。
请问这是什么原因? 谢谢!
不过你为什么要让他SLEEP这么长时间呢
你觉得我是个菜鸟吗? 连自己的问题也描述不清?!
接合你说的处理IO就停止的问题,我想问问你在处理IO获取路径的时候,有没有使用HttpContext.Current.Server.MapPath?
如果使用了,可能会有问题,在ApplicationStart的时候,HttpContext.Current还没有初始化,所以会抛异常但是还是有些奇怪,我再研究一下
实际上我的功能是这样:
1、开一个线程来处理一项耗时操作
2、另一个页面定时刷新来获取进度实际上和你的实现原理没有本质的差别,除了我没有在Application_Start里面做以外
HttpRuntime.AppDomainAppPath
来代替
HttpContext.Current.Server.MapPath(".")
但是我单独的去执行线程内的方法, 又是成功的。 真是百思不得其解。
或许我再研究一下, 真的很谢谢 timmy3310(tim) !
{
const int DELAY_TIMES = 1000 * 45 ; public ServerThread()
{
}
/// <summary>
/// 获取或设置是否中断线程
/// </summary>
bool CanExit = false ;
static Thread thread;
public void Start()
{
thread = new Thread(new ThreadStart(CheckProcess));
thread.Name = "Check News" ;
thread.Start();
Error.Log("后台线程于" + DateTime.Now.ToString() + " 启动! 状态为:" + thread.ThreadState.ToString());
} public void Stop()
{
CanExit = true ;
Error.Log("后台线程于" + DateTime.Now.ToString() + " 停止! ");
} #region 线程运行主体方法
/// <summary>
/// 执行检测
/// </summary>
void CheckProcess()
{
Error.Log("进入");
while(!CanExit)
{
lock(this)
{
//在线用户检查
CheckOnLine() ;
}
Thread.Sleep(DELAY_TIMES);
}
thread.Abort();
}
#endregion
#region 在线用户检查
void CheckOnLine()
{
for( int i=0;i<100000;i++ )
continue;
// Error.Log( "记录" );
} static ServerThread _Thread ;
public static ServerThread Instance
{
get
{
if(_Thread == null)
_Thread = new ServerThread() ;
return _Thread ;
}
} #endregion
}
{
ServerThread.Instance.Start();
}
我按照你提供的思路检查了一下, 确实存在这个问题:改变获取路径的方法, 写入日志成功, 线程也运行成功。 但是, 当我把真正要运行的逻辑加入时,线程又无法运行了。 那么现在的问题是:放置在线程中的方法有什么限制?是不是哪些类是不能使用的? 谢谢。出错代码如下:
#region 后台检测
/// <summary>
/// 检测日程安排是否到期
/// </summary>
public static void CheckSchedular()
{
LongWin.EnterpriseObjects.Error.Log("Check Schedular on " + DateTime.Now);
foreach(Schedular oSchedular in Schedular.GetAllNews())
{
if(oSchedular.UserID == 0) continue ;
if(oSchedular.State != SchedularState.ACTIVE) continue ;
//检测日程是否超期
if(oSchedular.TimeEnd < DateTime.Now)
{
oSchedular.State = SchedularState.OVERTIME ;
oSchedular.Save();
continue ;
}
//检测日程是否快开始
if(oSchedular.State == SchedularState.ACTIVE && oSchedular.LastAlertTime.Year == 1753)
{
DateTime d ;
switch(oSchedular.AheadAlertType)
{
case TimeType.Day:
d = oSchedular.TimeBegin.AddDays(-(double)oSchedular.AheadAlertNumber) ;
break;
case TimeType.Hour:
d = oSchedular.TimeBegin.AddHours(-(double)oSchedular.AheadAlertNumber) ;
break;
case TimeType.Minute:
d = oSchedular.TimeBegin.AddMinutes(-(double)oSchedular.AheadAlertNumber) ;
break;
case TimeType.Second:
d = oSchedular.TimeBegin.AddSeconds(-(double)oSchedular.AheadAlertNumber) ;
break;
default:
continue ;
}
if(d <= DateTime.Now )
{
oSchedular.LastAlertTime = DateTime.Now ;
oSchedular.Save();
ShortMessage oMessage= new ShortMessage();
oMessage.FromUserID = 0 ;
oMessage.ToUserID = oSchedular.UserID ;
oMessage.Message= String.Format("您安排的日程于{0}开始,请记得按时执行! <a href=Schedularview.aspx?id={1} target=mainFrame>日程查看</a>" , oSchedular.TimeBegin , oSchedular.ID);
oMessage.Save();
string[] sRelaPeoples = oSchedular.RelaPeoples.Split(',');
foreach(string s in sRelaPeoples)
{
if(s.Trim() == String.Empty) continue ;
try
{
oMessage.ID = 0 ;
oMessage.FromUserID = oSchedular.UserID ;
oMessage.ToUserID = int.Parse(s) ;
oMessage.Message= String.Format("我安排的日程于{0}开始,你是必须参与的人员之一,请记得按时执行! <a href=Schedularsview.aspx?id={1} target=mainFrame>日程查看</a>" , oSchedular.TimeBegin , oSchedular.ID);
oMessage.Date = DateTime.Now ;
oMessage.Save();
}
catch{}
}
}
}
} }
#endregion
是什么原因呢?
你把Schedular.GetAllNews()贴出来看看
/// 静态方法:获取所有新工作计划
/// </summary>
/// <returns>所有新的工作计划对象实例的集合</returns>
public static Schedular[] GetAllNews()
{
string sSql = string.Format("state=1") ; DataView dv = Schedular.DataSource.DefaultView ;
dv.RowFilter = sSql;
Schedular[] oSchedulars = new Schedular[dv.Count] ;
int i = 0;
foreach(DataRowView drv in dv)
{
oSchedulars[i] =new Schedular( drv.Row ) ;
i++;
}
return oSchedulars ;
}
会不会出在:
Schedular.DataSource这句上?是不是你获取数据的时候使用了什么不该使用的?
终于找到罪魁祸首了在线程跑到这里的时候
System.Web.HttpContext.Current这个实例还没有构造,是null实际上Web应用程序在接到请求的时候会这样:
1、是否第一次,是的话进行初始化,并引发ApplicationStart事件
2、从应用程序池获取一个应用程序来处理请求
3、构造一个HttpContext,放到线程数据槽中System.Web.HttpContext.Current这个属性实际上就是从当前的线程数据槽里面获取,像这样:
public HttpContext Current
{
get{
return CallContext.GetData("HttpContext"); //如果没记错的话
}
}
所以你在这里是不能用的,不过你可以使用:
HttpRuntime.Cache
是一样的
请问你的QQ号码是多少? 你在哪里呀? 有时间要多向你请教。 :)