Multithread problem with DataAbstract on server

Is the variable “this” available of the DataService class in multithread? I use this.Connection in my multithread server side program, it’s null. I use this.Session, it’s pop up exception “This service instance has not been activated yet”, my code as following:

FBackThreadExecuteBuilder = new System.Threading.Thread(new System.Threading.ThreadStart(_BackThreadExecuteBuilder));
FBackThreadExecuteBuilder.Start();

private void _BackThreadExecuteBuilder()
{
while (true)
{
this.Connection…//Null Value Exception
this.Session…//Exception:This service instance has not been activated yet
… …
}
}

how to solve this problem, any help will be greatly appreciated.

Hello

Please provide more complete code sample.

This means that the service instance you are trying to use has not been initialized properly.

The variable “this” is normally used in the methods of the DataService class. It’s just not available within the thread’s method. Here’s a more complete code:

    private class _ExecuteBuilderInfos
    {
        public int aBuildId, aElemId, aUserId;
        public object is_remind, buildtype, build_objid, storeprocname;

        public _ExecuteBuilderInfos(int aaBuildId, int aaElemId, int aaUserId,
            object ais_remind, object abuildtype, object abuild_objid, object astoreprocname)
        {
            aBuildId = aaBuildId;
            aElemId = aaElemId;
            aUserId = aaUserId;
            is_remind = ais_remind;
            buildtype = abuildtype;
            build_objid = abuild_objid;
            storeprocname = astoreprocname;
        }
    }
    private System.Threading.Thread FBackThreadExecuteBuilder = null; //后台执行自动生成配置的线程
    private static readonly List<_ExecuteBuilderInfos> _ToExecuteBuilderInfosList = new List<_ExecuteBuilderInfos>();
    private static System.Threading.ManualResetEvent FMRE = new System.Threading.ManualResetEvent(false); //用于线程等待
    private void AddToQueueExecuteBuilder(int aaBuildId, int aaElemId, int aaUserId,
        object ais_remind, object abuildtype, object abuild_objid, object astoreprocname)
    {
        lock (_ToExecuteBuilderInfosList)
        {
            _ToExecuteBuilderInfosList.Add(new _ExecuteBuilderInfos(aaBuildId, aaElemId, aaUserId,
                ais_remind, abuildtype, abuild_objid, astoreprocname));
            if (_ToExecuteBuilderInfosList.Count == 1) FMRE.Set();
        }
    }
    private void _BackThreadExecuteBuilder()
    {
        //后台循环检测
        _ExecuteBuilderInfos lItem;
        while (true)
        {
            lItem = null; bool lbWait = false;
            lock (_ToExecuteBuilderInfosList)
            {
                if (_ToExecuteBuilderInfosList.Count > 0) lItem = _ToExecuteBuilderInfosList[0];
                else
                {
                    lbWait = true;
                    FMRE.Reset();
                }
            }
            if (lbWait) FMRE.WaitOne();
            if (lItem != null)
            {
                try
                {
                    int loObjInstId; string loPromptInfo;
                    whdErrCode ret = whdAsyncElementBuildExecute(true, lItem.aBuildId, lItem.aElemId, lItem.aUserId, lItem.is_remind, lItem.buildtype,
                        lItem.build_objid, lItem.storeprocname, out loObjInstId, out loPromptInfo);
                    //Using "this.Connection" will throw a null exception in whdAsyncElementBuildExecute
                    //Using "this.Session" will throw an exception: "This service instance has not been activated yet" in whdAsyncElementBuildExecute
                }
                catch (Exception ex)
                {
                    ErrorLogAndNotify(0, "_BackThreadExecuteBuilder2", "后台异步执行自动生成配置出错:" +
                        ex.Message + "\nStackTrace:" + ex.StackTrace);
                }
                finally
                {
                    lock (_ToExecuteBuilderInfosList)
                    {
                        _ToExecuteBuilderInfosList.Remove(lItem);
                    }
                }
            }
            System.Threading.Thread.Sleep(5);
        }
    }
    public whdErrCode whdElementBuildExecute(int aBuildId, int aElemId, int aUserId, out int aoObjInstId)
    {
        whdErrCode ret = new whdErrCode();
        ret.errCode = 0;
        ret.errMsg = "成功";
        string lPromptInfo = "";
        aoObjInstId = 0;

        //获取必要的参数
        object is_remind, buildtype, build_objid, storeprocname, synctype;
        GetSQLValueEx(string.Format(
            "select is_remind, buildtype, build_objid, storeprocname, synctype " +
            "from t_builder where buildid = {0}", aBuildId),
            out is_remind, out buildtype, out build_objid, out storeprocname, out synctype);

        if (GD.IsNullInteger(synctype, 1) == 1)
        {
            //==1 synchronization,同步执行方法
            ret = whdAsyncElementBuildExecute(false, aBuildId, aElemId, aUserId, is_remind, buildtype, 
                build_objid, storeprocname, out aoObjInstId, out lPromptInfo);
            //It can use "this" normally in whdAsyncElementBuildExecute
        }
        else
        {
            //==2 asynchronous,异步执行方法:把请求添加到队列中,排队执行
            if (FBackThreadExecuteBuilder == null)
            {
                FBackThreadExecuteBuilder = new System.Threading.Thread(
                    new System.Threading.ThreadStart(_BackThreadExecuteBuilder));
                FBackThreadExecuteBuilder.Start();
            }
            AddToQueueExecuteBuilder(aBuildId, aElemId, aUserId, is_remind, buildtype, build_objid, storeprocname);

        }

        if (!string.IsNullOrWhiteSpace(lPromptInfo))
        {
            ret.errMsg = (ret.errMsg == "成功" ? "" : ret.errMsg + " - ") + lPromptInfo;
        }
        return ret;
    }

Is this code a part of a class inherited from the DataAbstractService class ? If so then how exactly this code is started - is it started during execution of the service method called from a remote client or you do start it from some server code?

Starting background thread with code that uses the same service instance is a bad idea. Service instance will be recycled and will become invalid once the service method execution is completed, so all attempts to access later it from a background thread will result in undefined behavior.

You need to instantiate own separate service instance using code like

var service = new DataService();
try
{
    service.Activate(sessionId, false);

    // Do the work
}
finally
{
    service.Deactivate(sessionId);
}

sessionId here should be a valid session Id if the worker code needs to access session values

Yes, It’s a part of a class inherited from the DataAbstractService class.
I don’t know how it started, I didn’t find the start code. Probably because it was generated by the wizard.

Can’t it use thread in the class inherited from the DataAbstractService class ?
How to implement asynchronous calls?

You can. You just have to properly handle objects lifespan to avoid interactions with disposed objects.

What exactly do you mean? It is up to the client to perform sync or async calls to the server. Server-side code is the same in both cases.

Could you say what exactly are you trying to achieve with this code?

Is it every time the client invokes the server method, it will create an instance of the DataService?

I am trying to implement a server-side method that internally determines whether it needs to execute some code asynchronously.

It depends on the class factory used by the service: Class Factories (.NET & Delphi)

The default class factory creates new service instances on each request.

What is the reason for this?

I see. thank you very much.