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

解决方案 »

  1.   

    有个小问题想问一下你是在Web应用中做的吗?
    如果是,你的这个对象的实例在哪里定义的?如果是在某个页面里,实例可能被释放了,你试试把它写成静态的实例
      

  2.   

    在该类中还有一个属性:
    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();
    }
      

  3.   

    如果线程开始的时侯,而 UserOnLine.Items中没有USER的话,线程不是就会sleep1000*45了吗?是不是这个原因呢.是不是休眠造成的,所以他会不处于RUNNING状态.还有JOIN()方法的原因,我也赞成楼上大哥说的,你加上他的目的何在呢.
    我是初学者,有时说的过于浅溥,
      

  4.   

    1、SLEEP不会造成线程中止。
    2、JOIN() 只是同步线程,用于后面的代码可以获取线程的正确状态。
    应该不是以上问题。 不过, 还是谢谢你们。 :)
      

  5.   

    我试过你的代码了
    确实如此,很是奇怪我现在的项目里有类似的功能,但是我的做法与你有一点不同:
    1、在Global里面有一个静态的实例处理功能
    2、在某一个页面点击按钮后new一个线程来启动该实例的某个方法我想了半天,实际上和你的几乎没有差别我要下班了,回去好好想想,明天再来讨论
      

  6.   

    哈哈,很简单的问题,其实你的线程一直是正确运行的,只不过你那条调试信息语句是紧接者线程实例创建启动后打印的,打印时可能新线程根本没来的急启动,也可能确实启动,还可能有其他状态,我建议你吧调试语句放到线程对象的启动代码了,而不是放在线程创建者的代码里。
    thread.Start();
    thread.Join();
    Error.Log("后台线程于" + DateTime.Now.ToString() + " 启动! 状态为:" + thread.ThreadState.ToString()); 
    ^^^^^^^^^^^^^^^^^^^^^^^^^---- 这句话存在线程竞争CPU的不确定性!!!!!
      

  7.   

    请查看thread.Join();的功能。
      

  8.   

    thread.Join(); 就是用于同步线程的。 线程是否启动我一定会知道的。 因为这个线程里会有数据库更新操作。 不止我贴出来这么少。 ^_^
      

  9.   

    timmy3310(tim): 
    请问你在线程方法主体内做了哪些操作?
    我刚刚测试了一下, 我在线程方法中写了一个循环, 其他没有任何操作, 此时线程是正常运行的。
    但是,一旦在循环中加入任何操作,如进行系统IO操作, 线程即刻自动中止。 
    请问这是什么原因? 谢谢!
      

  10.   

    噢,大家说的我好晕噢,好好的看.
    不过你为什么要让他SLEEP这么长时间呢
      

  11.   

    zhg_best2000 :
    你觉得我是个菜鸟吗? 连自己的问题也描述不清?! 
      

  12.   

    昨天我把你的代码试了试
    接合你说的处理IO就停止的问题,我想问问你在处理IO获取路径的时候,有没有使用HttpContext.Current.Server.MapPath?
    如果使用了,可能会有问题,在ApplicationStart的时候,HttpContext.Current还没有初始化,所以会抛异常但是还是有些奇怪,我再研究一下
      

  13.   

    我的代码里面处理了数据库
    实际上我的功能是这样:
    1、开一个线程来处理一项耗时操作
    2、另一个页面定时刷新来获取进度实际上和你的实现原理没有本质的差别,除了我没有在Application_Start里面做以外
      

  14.   

    刚刚我又试了一下果然是这个问题,我不使用MapPath方法来获取路径就行了HttpContext是在每一次请求进来的时候才会构造,在ApplicationStart的时候没有实例你可以使用:
    HttpRuntime.AppDomainAppPath
    来代替
    HttpContext.Current.Server.MapPath(".")
      

  15.   

    谢谢, 我把线程启动的方法放到一个页面的点击事件中去触发, 还是不能启动线程。
    但是我单独的去执行线程内的方法, 又是成功的。 真是百思不得其解。
    或许我再研究一下, 真的很谢谢 timmy3310(tim) !
      

  16.   

    public class ServerThread
    {
    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
    }
      

  17.   

    protected void Application_Start(Object sender, EventArgs e)
    {
    ServerThread.Instance.Start();
    }
      

  18.   

    这是我粘贴了你的代码后改动了一点这段代码测试成功了,Error.Log里面只是打开当前目录下的Log文件Append一段文本
      

  19.   

    timmy3310(tim):
    我按照你提供的思路检查了一下, 确实存在这个问题:改变获取路径的方法, 写入日志成功, 线程也运行成功。 但是, 当我把真正要运行的逻辑加入时,线程又无法运行了。 那么现在的问题是:放置在线程中的方法有什么限制?是不是哪些类是不能使用的? 谢谢。出错代码如下:
    #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
      

  20.   

    把你的ShortMessage 类代码贴出来看看实际上是这样,线程里面的方法没有什么限制限制是出现在某些具有特定上下文才能访问的类中,比如刚刚出现问题的HttpContext.Current实例,这个实例要在处理请求的时候才会构造,在ApplicationStart的时候,这个实例还没有构造,所以出现了问题一般来说,在ApplicationStart、End、StartRequest这些事件当中,Session、Request、Response这些对象是不能使用的我想问题可能出现在你的逻辑的某个地方使用了这些当前上下文中不能使用的对象
      

  21.   

    我真是不确定了, 我刚刚测试了一下, 发现问题出现在Schedular.GetAllNews()这个方法上,线程就在执行这个方法时自动中止了, 而这个方法里所做的事就是获取SCHEDULAR这个类中的静态属性(类型是DATATABLE)然后根据DATAROW实例化成对象数组。
    是什么原因呢?
      

  22.   

    按照你说的,应该是没问题
    你把Schedular.GetAllNews()贴出来看看
      

  23.   

    /// <summary>
    /// 静态方法:获取所有新工作计划
    /// </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 ;
    }
      

  24.   

    就这么看应该是没甚么问题啊
    会不会出在:
    Schedular.DataSource这句上?是不是你获取数据的时候使用了什么不该使用的?
      

  25.   

    Schedular.DataSource 这是一个类上的静态属性, 在这个属性中引用了System.Web.HttpContext.Current.Cache, 是这个影响了?
      

  26.   

    对,肯定是
    终于找到罪魁祸首了在线程跑到这里的时候
    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
    是一样的
      

  27.   

    好象是CheckSchedular方法里面出错, 我检查一下, 应该能够解决了, 谢谢了。 
    请问你的QQ号码是多少? 你在哪里呀? 有时间要多向你请教。 :)
      

  28.   

    435500不过不太经常上MSN:[email protected]:)