最近做一个项目,用WebService做一个数据库查询,查询需要对多个数据库执行查询,我在主程序中使用多个线程分别来各自和一个数据库建立连接,执行完成后将结果放入一个公共变量。现在有一个问题是数据库查询的结果由于网络原因会有快慢之分,为了缩短相应我在主程序中设置了一个时间值一旦超出该时间值主程序就会把已经得到的结果返回不再等待执行较慢的线程,执行较慢的线程如果没有将结果放入公共变量执行完成后会把数据放入缓冲区,下次执行时就不必再建立连接了。
但是现在的问题是主程序在执行了返回(return)后程序就结束了,子线程这时候显然会由于主程序的结束而产生异常,无法将结果正常放入缓冲区。有没有办法可以解决。期待高手指点一二!

解决方案 »

  1.   

    >>但是现在的问题是主程序在执行了返回(return)后程序就结束了,子线程这时候显然会由于主程序的结束而产生异常,无法将结果正常放入缓冲区实际情况真是这样吗?我觉得不是吧。
      

  2.   

    我觉得应该是这样的,因为程序return后就结束了,子线程还会继续运行吗?
      

  3.   

    我觉得线程分两种,一种是后台运行的,一种是前台运行的。
    后台的就是主程序完成后,子线程还会继续运行的,直到完成。具体的属性设置是:IsBackground
      

  4.   

    Thanks 对于WebService到地址哪一种,是不是可以具体指定?
      

  5.   

    不是这样的,WebService进程不会因为return语句就结束,只要进程不结束,线程也不会自动退出, 建议你检查一下是不是线程本身读数据出了异常?
      

  6.   

    看到了,可以设置一个IsBackground的属性,这样是不是就可以在主程序完成后子线程继续执行,直到得出结果。在这时主程序中的变量是不是仍然可用?
      

  7.   

    再说,一般通过new Thread(new ThreadStart())创建的线程都是前台线程,更不会因为return语句造成线程退出了!
      

  8.   

    >>后台的就是主程序完成后,子线程还会继续运行的,直到完成。
    这句话是错误的,后台线程不会阻止进程退出,只要进程退出了,后台线程自动终止;而前台线程才会阻止进程退出!
      

  9.   

    那么进程执行return后由进程发起的尚未结束的线程会发生异常吗?还是会执行完成后再退出?
      

  10.   

    只有所有的前台线程都退出了,进程才会退出;建议你启动永不退出的线程,比如定时Sleep(100),然后测试一下看看问题是否解决了。
      

  11.   

    变异可以通过,但是一旦在方法前面加上[WebMethod]出错,下面是错误信息:
    类型 System.ComponentModel.ISite 的成员 System.ComponentModel.MarshalByValueComponent.Site 是接口,因此无法将其序列化。 
    说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 异常详细信息: System.NotSupportedException: 类型 System.ComponentModel.ISite 的成员 System.ComponentModel.MarshalByValueComponent.Site 是接口,因此无法将其序列化。源错误: 执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。  堆栈跟踪: 
    [NotSupportedException: 类型 System.ComponentModel.ISite 的成员 System.ComponentModel.MarshalByValueComponent.Site 是接口,因此无法将其序列化。]
       System.Xml.Serialization.TypeScope.ImportTypeDesc(Type type, Boolean canBePrimitive, MemberInfo memberInfo) +1283
       System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo source, Boolean directReference) +50
       System.Xml.Serialization.StructModel.GetPropertyModel(PropertyInfo propertyInfo) +54
       System.Xml.Serialization.StructModel.GetFieldModel(MemberInfo memberInfo) +88
       System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns) +1536
       System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns) +662
       System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, Boolean repeats) +440[InvalidOperationException: 反射类型“System.Data.DataTable”时出错。]
       System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, Boolean repeats) +1059
       System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType) +8238
       System.Xml.Serialization.XmlReflectionImporter.ImportMemberMapping(XmlReflectionMember xmlReflectionMember, String ns, XmlReflectionMember[] xmlReflectionMembers) +795
       System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement) +300[InvalidOperationException: 反射“GetDTResult”时出错。]
       System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement) +607
       System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(String elementName, String ns, XmlReflectionMember[] members, Boolean hasWrapperElement) +108
       System.Web.Services.Protocols.SoapReflector.ImportMembersMapping(XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, Boolean serviceDefaultIsEncoded, Boolean rpc, SoapBindingUse use, SoapParameterStyle paramStyle, String elementName, String elementNamespace, Boolean nsIsDefault, XmlReflectionMember[] members, Boolean validate) +169
       System.Web.Services.Protocols.SoapReflector.ReflectMethod(LogicalMethodInfo methodInfo, Boolean client, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, String defaultNs) +2860[InvalidOperationException: 无法反射方法 ThreadTest.GetDT。]
       System.Web.Services.Protocols.SoapReflector.ReflectMethod(LogicalMethodInfo methodInfo, Boolean client, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, String defaultNs) +5415
       System.Web.Services.Description.SoapProtocolReflector.ReflectMethod() +130
       System.Web.Services.Description.ProtocolReflector.ReflectBinding(ReflectedBinding reflectedBinding) +1818
       System.Web.Services.Description.ProtocolReflector.Reflect() +506
       System.Web.Services.Description.ServiceDescriptionReflector.ReflectInternal(ProtocolReflector[] reflectors) +495
       System.Web.Services.Description.ServiceDescriptionReflector.Reflect(Type type, String url) +112
       System.Web.Services.Protocols.DocumentationServerType..ctor(Type type, String uri) +158
       System.Web.Services.Protocols.DocumentationServerProtocol.Initialize() +269
       System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing) +106[InvalidOperationException: 无法处理请求。]
       System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing) +205
       System.Web.Services.Protocols.WebServiceHandlerFactory.CoreGetHandler(Type type, HttpContext context, HttpRequest request, HttpResponse response) +82[InvalidOperationException: 未能处理请求。]
       System.Web.Services.Protocols.WebServiceHandlerFactory.CoreGetHandler(Type type, HttpContext context, HttpRequest request, HttpResponse response) +154
       System.Web.Services.Protocols.WebServiceHandlerFactory.GetHandler(HttpContext context, String verb, String url, String filePath) +94
       System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, String path, String pathTranslated, Boolean useAppConfig) +699
       System.Web.MapHandlerExecutionStep.System.Web.HttpApplication+IExecutionStep.Execute() +95
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +173 
      

  12.   

    帖出出错部分的源代码,估计是 WebMethod 的参数或者返回值无法序列化的问题。
      

  13.   

    public class ThreadTest : System.Web.Services.WebService
    {
    DataTable PubTable = null;
    int FinishNum = 0;
    bool Lock = false;
    bool DataOK = false;
    Cache DBCache = new Cache();
    public DataTable GetDate()
    {
    ThreadStart TS = new ThreadStart(GetDBTable);
    Thread T1 = new Thread(TS);
    T1.Name = "Thread1";
    T1.Start();
    Thread T2 = new Thread(TS);
    T2.Name = "Thread2";
    T2.Start();
    Thread.Sleep(500);
    DataOK = true;
    DataTable Dt = PubTable;
    if(FinishNum<2&&Lock)Thread.Sleep(100);
    return Dt;
    }
    public viod GetDBTable()
    {
    ...
    }
    ...
    }
      

  14.   

    GetDBTable()中是数据库连接的代码,错误信息中没有说在这些代码中有错误
      

  15.   

    DataTable 是不可以作为WebMethod的返回值的!改为返回DataSet:DataSet ds = new DataSet();
    ds.Tables.Add(Dt);
    return ds;
      

  16.   

    OK问题解决!但是就是不知道多线程执行的效果怎么样?Thanks!
      

  17.   

    >>if(FinishNum<2&&Lock)Thread.Sleep(100);
    可能要改为
    while (FinishNum<2&&Lock)Thread.Sleep(100);还是那句话:return不会引起线程中止的
      

  18.   

    >> ... 但是数据却没有被正常传递具体点。
      

  19.   

    public class Threads : System.Web.UI.Page
    {
    public int i=0;
    public DataSet Ds = new DataSet();
    SqlConnection Conn = new SqlConnection("Server=;UID=sa;PWD=;");
    private void Page_Load(object sender, System.EventArgs e)
    {
    // 在此处放置用户代码以初始化页面
    ThreadStart Ts = new ThreadStart(Th);
    Thread T1 = new Thread(Ts);
    T1.Name = "Thread1";
    T1.Start();
    Thread T2 = new Thread(Ts);
    T2.Name = "Thread2";
    T2.Start();
    Thread.Sleep(5000);
    if(Ds.Tables.Count>0)
    {
    DataTable Dt = Ds.Tables[0];
    for(int i=0;i<Dt.Rows.Count;i++)
    {
    DataRow Dr = Dt.Rows[i];
    Response.Write(Dr[0] + "&nbsp;" + Dr[1] + "&nbsp;" + Dr[2]);
    }
    }
    //Response.Write(i.ToString());
    Response.End(); }
    private void Th()
    {
    //Response.Write(Thread.CurrentThread.Name + ":" + i);
    Conn.Open();
    SqlDataAdapter Sda = new SqlDataAdapter("Select [ID],[UserName],UserLable From [User]",Conn);
    DataSet DsT = new DataSet();
    Sda.Fill(DsT);
    Conn.Close();
    Ds.Tables.Add(DsT.Tables[0].Clone());
    if(Ds.Tables.Count>0)
    {
    DataTable Dt = Ds.Tables[0];
    for(int i=0;i<Dt.Rows.Count;i++)
    {
    DataRow Dr = Dt.Rows[i];
    Response.Write(Dr[0] + "&nbsp;" + Dr[1] + "&nbsp;" + Dr[2]);
    }
    }
    Sda.Dispose();
    }
    }
    得到的结果是空的
      

  20.   

    我发现一个问题我把Response.Write(Thread.CurrentThread.Name);放到Sda.Fill(DsT);前面就可以输出Thread1Thread2详细代码如下:
    private void Th()
    {
    //Response.Write(Thread.CurrentThread.Name + ":" + i);
    Conn.Open();
    SqlDataAdapter Sda = new SqlDataAdapter("Select UB_User_ID,UB_User_Name,UB_User_Lable From UserBasic",Conn);
    DataSet DsT = new DataSet();
    Response.Write(Thread.CurrentThread.Name);
    Sda.Fill(DsT);
    Conn.Close();
    Ds.Tables.Add(DsT.Tables[0].Clone());
    if(DsT.Tables.Count>0)
    {
    DataTable Dt = DsT.Tables[0];
    for(int i=0;i<Dt.Rows.Count;i++)
    {
    DataRow Dr = Dt.Rows[i];
    Response.Write(Dr[0] + "&nbsp;" + Dr[1] + "&nbsp;" + Dr[2]);
    }
    }
    Sda.Dispose();
    }
    但是当我把Response.Write(Thread.CurrentThread.Name);放到Sda.Fill(DsT);后面面就什么也没有了详细代码如下:
    private void Th()
    {
    //Response.Write(Thread.CurrentThread.Name + ":" + i);
    Conn.Open();
    SqlDataAdapter Sda = new SqlDataAdapter("Select UB_User_ID,UB_User_Name,UB_User_Lable From UserBasic",Conn);
    DataSet DsT = new DataSet();
    Sda.Fill(DsT);
    Response.Write(Thread.CurrentThread.Name);
    Conn.Close();
    Ds.Tables.Add(DsT.Tables[0].Clone());
    if(DsT.Tables.Count>0)
    {
    DataTable Dt = DsT.Tables[0];
    for(int i=0;i<Dt.Rows.Count;i++)
    {
    DataRow Dr = Dt.Rows[i];
    Response.Write(Dr[0] + "&nbsp;" + Dr[1] + "&nbsp;" + Dr[2]);
    }
    }
    Sda.Dispose();
    }
      

  21.   

    DsT.Tables[0].Clone() 应该是 DsT.Tables[0].Copy();
    Clone只复制结构,不复制DataRow
      

  22.   

    我现在直接输出的子线程中的DataSet中的DataTable但是还是没有结果
    private void Th()
    {
    //Response.Write(Thread.CurrentThread.Name + ":" + i);
    SqlConnection Conn = new SqlConnection("Server=;UID=;PWD=");
    Conn.Open();
    SqlDataAdapter Sda = new SqlDataAdapter("Select top 1 [ID],[UserName],[Lable] From User",Conn);
    DataSet DsT = new DataSet();
    Sda.Fill(DsT);
    Response.Write(Thread.CurrentThread.Name);
    Conn.Close();
    //DsT.Tables[0].Clone();
    DataTable Dt = DsT.Tables[0];
    for(int i=0;i<Dt.Rows.Count;i++)
    {
    DataRow Dr = Dt.Rows[i];
    Response.Write(Dr[0] + "&nbsp;" + Dr[1] + "&nbsp;" + Dr[2]);
    }
    Sda.Dispose();
    }
      

  23.   

    你把 Response.End() 去掉看看。