C# 具有返回类型的方法的线程池

C# 具有返回类型的方法的线程池,c#,C#,我有一个名为InitializeCRMService()的方法,它返回ioorganizationservice的对象。现在,我定义了一个名为GetConnection(stringthread)的不同方法,它根据传递给它的参数调用InitializeCRMService()。如果传递给GetConnection的字符串是单线程的,它将启动initializermservice()方法的单线程实例,但是如果传递的字符串是多线程的,我需要使用线程池,在这里我需要将方法传递给QueueUserWor

我有一个名为
InitializeCRMService()
的方法,它返回
ioorganizationservice
的对象。现在,我定义了一个名为
GetConnection(stringthread)
的不同方法,它根据传递给它的参数调用
InitializeCRMService()
。如果传递给
GetConnection
的字符串是单线程的,它将启动
initializermservice()
方法的单线程实例,但是如果传递的字符串是多线程的,我需要使用线程池,在这里我需要将方法传递给
QueueUserWorkItem
。方法
InitializeCrmsService
没有输入参数。它只返回一个服务对象。请在
GetConnection
方法的代码块下方找到:

public void GetConnection(string thread)
{
    ParallelOptions ops = new ParallelOptions();

    if(thread.Equals("one"))
    {
        Parallel.For(0, 1, i =>
        {
            dynamic serviceObject = InitializeCRMService();       
        });
    }
    else if (thread.Equals("multi"))
    {
        // HERE I NEED TO IMPLEMENT MULTITHREADING USING THREAD POOL 
        // AND NOT PARALLEL FOR LOOP......
        // ThreadPool.QueueUserWorkItem(new WaitCallback(InitializeCRMService));
    }
}
请注意,我的方法
InitializeCRMService()
具有服务对象的返回类型


请告诉我如何实现它。

由于您希望在插槽可用时在线程池中执行InitializeCrmsService,并且只执行一次,因此解决方案取决于您希望如何处理InitializeCrmsService的返回值

如果你只想忽略它,到目前为止,我有两个选择


选项1 另一方面,如果您需要将其传递到某个地方存储并在以后重新使用,您可以这样做:

public void GetConnection(string thread)
{
    //I found that ops is not being used
    //ParallelOptions ops = new ParallelOptions();

    if(thread.Equals("one"))
    {
        Parallel.For(0, 1, i =>
        {
            //It seems to me a good idea to take the same path here too
            //dynamic serviceObject = InitializeCRMService();
            Store(InitializeCRMService());
        });
    }
    else if (thread.Equals("multi"))
    {
        ThreadPool.QueueUserWorkItem
        (
             new WaitCallback
             (
                 (_) =>
                 {
                      Store(InitializeCRMService());
                 }
             )
        );
    }
}
private void Store(dynamic serviceObject)
{
    //store serviceObject somewhere you can use it later.
    //Depending on your situation you may want to
    // set a flag or use a ManualResetEvent to notify
    // that serviceObject is ready to be used.
    //Any pre proccess can be done here too.
    //Take care of thread affinity,
    // since this may come from the ThreadPool
    // and the consuming thread may be another one,
    // you may need some synchronization.
}

哪里的商店应该是这样的:

public void GetConnection(string thread)
{
    //I found that ops is not being used
    //ParallelOptions ops = new ParallelOptions();

    if(thread.Equals("one"))
    {
        Parallel.For(0, 1, i =>
        {
            //It seems to me a good idea to take the same path here too
            //dynamic serviceObject = InitializeCRMService();
            Store(InitializeCRMService());
        });
    }
    else if (thread.Equals("multi"))
    {
        ThreadPool.QueueUserWorkItem
        (
             new WaitCallback
             (
                 (_) =>
                 {
                      Store(InitializeCRMService());
                 }
             )
        );
    }
}
private void Store(dynamic serviceObject)
{
    //store serviceObject somewhere you can use it later.
    //Depending on your situation you may want to
    // set a flag or use a ManualResetEvent to notify
    // that serviceObject is ready to be used.
    //Any pre proccess can be done here too.
    //Take care of thread affinity,
    // since this may come from the ThreadPool
    // and the consuming thread may be another one,
    // you may need some synchronization.
}
现在,如果需要允许类的客户端访问serviceObject,可以采用以下方法:

//Note: I marked it as partial because there may be other code not showed here
// in particular I will not write the method GetConnection again. That said...
// you can have it all in a single block in a single file without using partial.
public partial class YourClass
{
    private dynamic _serviceObject;

    private void Store(dynamic serviceObject)
    {
        _serviceObject = serviceObject;
    }

    public dynamic ServiceObject
    {
        get
        {
            return _serviceObject;
        }
    }
}
但这并不能解决所有的问题。特别是,如果希望线程等待serviceObject就绪:

public partial class YourClass
{
    private ManualResetEvent _serviceObjectWaitHandle = new ManualResetEvent(false);
    private dynamic _serviceObject;


    private void Store(dynamic serviceObject)
    {
        _serviceObject = serviceObject;
        //If you need to do some work as soon as _serviceObject is ready...
        // then it can be done here, this may still be the thread pool thread.
        //If you need to call something like the UI...
        // you will need to use BeginInvoke or a similar solution.
        _serviceObjectWaitHandle.Set();
    }

    public void WaitForServiceObject()
    {
            //You may also expose other overloads, just for convenience.
            //This will wait until Store is executed
            //When _serviceObjectWaitHandle.Set() is called
            // this will let other threads pass.
            _serviceObjectWaitHandle.WaitOne();
    }

    public dynamic ServiceObject
    {
        get
        {
            return _serviceObject;
        }
    }
}

不过,我还没有涵盖所有的场景。实际上。。。如果多次调用GetConnection,会发生什么情况?我们需要决定是否允许这样做,如果允许,我们如何处理旧的serviceObject?(我们是否需要调用某个函数来消除它?)。如果我们允许多个线程同时调用GetConnection,这可能会有问题。所以默认情况下,我会说我们没有,但我们也不想阻止其他线程

解决方案是什么?如下:

//This is another part of the same class
//This one includes GetConnection
public partial class YourClass
{
    //1 if GetConnection has been called, 0 otherwise
    private int _initializingServiceObject;

    public void GetConnection(string thread)
    {
        if (Interlocked.CompareExchange(ref _initializingServiceObject, 1, 0) == 0)
        {
            //Go on, it is the first time GetConnection is called

            //I found that ops is not being used
            //ParallelOptions ops = new ParallelOptions();
            if(thread.Equals("one"))
            {
                Parallel.For(0, 1, i =>
                {
                    //It seems to me a good idea to take the same path here too
                    //dynamic serviceObject = InitializeCRMService();
                    Store(InitializeCRMService());
                });
            }
            else if (thread.Equals("multi"))
            {
                ThreadPool.QueueUserWorkItem
                (
                     new WaitCallback
                     (
                         (_) =>
                         {
                              Store(InitializeCRMService());
                         }
                     )
                );
            }
        }
    }
}

最后,如果我们允许多线程使用_serviceObject,而_serviceObject不是线程安全的,我们可能会遇到麻烦。使用监视器或读写锁是解决这个问题的两种选择

你还记得这个吗

    public dynamic ServiceObject
    {
        get
        {
            return _serviceObject;
        }
    }
好的,您想让调用者在_serviceObject处于阻止其他线程进入的上下文中时访问它(请参见System.Threading.Monitor),并确保它停止使用它,然后离开我前面提到的上下文

现在考虑调用方线程仍然可以存储某处的Service对象的副本,然后离开同步化,然后用yServices对象做一些事情,并且当另一个线程使用它时可能发生这种情况。 谈到穿线,我习惯于考虑每个角落的情况。但是,如果您可以控制调用线程,那么只需使用上面显示的属性就可以很好地完成。如果你不。。。让我们谈谈,我警告你,它可能是广泛的


选项2 这是一种完全不同的行为,您在问题中提出的建议使我认为您可能打算返回serviceObject。在这种情况下,它不会在线程之间共享,一次可以有多个serviceObject。任何需要的同步都留给调用者

好的,这可能就是你一直在寻找的:

public void GetConnection(string thread, Action<dynamic> callback)
{
    if (ReferenceEquals(callback, null))
    {
        throw new ArgumentNullException("callback");
    }
    //I found that ops is not being used
    //ParallelOptions ops = new ParallelOptions();
    if(thread.Equals("one"))
    {
        Parallel.For(0, 1, i =>
        {
            callback(InitializeCRMService());
        });
    }
    else if (thread.Equals("multi"))
    {
        ThreadPool.QueueUserWorkItem
        (
             new WaitCallback
             (
                 (_) =>
                 {
                      callback(InitializeCRMService());
                 }
             )
        );
    }
}
public void GetConnection(字符串线程、操作回调)
{
if(ReferenceEquals(回调,null))
{
抛出新的ArgumentNullException(“回调”);
}
//我发现ops没有被使用
//ParallelOptions ops=新的ParallelOptions();
if(线程等于(“一”))
{
对于(0,1,i=>
{
回调(初始化ECRMSERVICE());
});
}
else if(线程等于(“多”))
{
ThreadPool.QueueUserWorkItem
(
新的等待回调
(
(_) =>
{
回调(初始化ECRMSERVICE());
}
)
);
}
}
回调应该是什么样子?好的,只要线程之间没有共享它就可以了。为什么?因为调用GetConnection的每个线程都会传递自己的回调操作,并将接收不同的serviceObject,所以一个线程对它所做的事情不会影响另一个线程对它所做的事情(因为它不是同一个serviceObject)

除非您想让一个线程调用它,然后与其他线程共享它,在这种情况下,这是调用者的问题,它将在另一个地方解决



最后一件事,您可以使用枚举来表示当前在字符串线程中传递的选项。事实上,由于只有两个选项,您可以考虑使用BoL,除非将来可能出现更多的情况。

< P>因为在槽可用时,在线程池中执行RealAlxErrMService,并且只执行一次,解决方案取决于您希望如何处理InitializeCrmsService的返回值

如果你只想忽略它,到目前为止,我有两个选择


选项1 另一方面,如果您需要将其传递到某个地方存储并在以后重新使用,您可以这样做:

public void GetConnection(string thread)
{
    //I found that ops is not being used
    //ParallelOptions ops = new ParallelOptions();

    if(thread.Equals("one"))
    {
        Parallel.For(0, 1, i =>
        {
            //It seems to me a good idea to take the same path here too
            //dynamic serviceObject = InitializeCRMService();
            Store(InitializeCRMService());
        });
    }
    else if (thread.Equals("multi"))
    {
        ThreadPool.QueueUserWorkItem
        (
             new WaitCallback
             (
                 (_) =>
                 {
                      Store(InitializeCRMService());
                 }
             )
        );
    }
}
private void Store(dynamic serviceObject)
{
    //store serviceObject somewhere you can use it later.
    //Depending on your situation you may want to
    // set a flag or use a ManualResetEvent to notify
    // that serviceObject is ready to be used.
    //Any pre proccess can be done here too.
    //Take care of thread affinity,
    // since this may come from the ThreadPool
    // and the consuming thread may be another one,
    // you may need some synchronization.
}

哪里的商店应该是这样的:

public void GetConnection(string thread)
{
    //I found that ops is not being used
    //ParallelOptions ops = new ParallelOptions();

    if(thread.Equals("one"))
    {
        Parallel.For(0, 1, i =>
        {
            //It seems to me a good idea to take the same path here too
            //dynamic serviceObject = InitializeCRMService();
            Store(InitializeCRMService());
        });
    }
    else if (thread.Equals("multi"))
    {
        ThreadPool.QueueUserWorkItem
        (
             new WaitCallback
             (
                 (_) =>
                 {
                      Store(InitializeCRMService());
                 }
             )
        );
    }
}
private void Store(dynamic serviceObject)
{
    //store serviceObject somewhere you can use it later.
    //Depending on your situation you may want to
    // set a flag or use a ManualResetEvent to notify
    // that serviceObject is ready to be used.
    //Any pre proccess can be done here too.
    //Take care of thread affinity,
    // since this may come from the ThreadPool
    // and the consuming thread may be another one,
    // you may need some synchronization.
}
现在,如果需要允许类的客户端访问serviceObject,可以采用以下方法:

//Note: I marked it as partial because there may be other code not showed here
// in particular I will not write the method GetConnection again. That said...
// you can have it all in a single block in a single file without using partial.
public partial class YourClass
{
    private dynamic _serviceObject;

    private void Store(dynamic serviceObject)
    {
        _serviceObject = serviceObject;
    }

    public dynamic ServiceObject
    {
        get
        {
            return _serviceObject;
        }
    }
}
但这并不能解决所有的问题。特别是,如果希望线程等待serviceObject就绪:

public partial class YourClass
{
    private ManualResetEvent _serviceObjectWaitHandle = new ManualResetEvent(false);
    private dynamic _serviceObject;


    private void Store(dynamic serviceObject)
    {
        _serviceObject = serviceObject;
        //If you need to do some work as soon as _serviceObject is ready...
        // then it can be done here, this may still be the thread pool thread.
        //If you need to call something like the UI...
        // you will need to use BeginInvoke or a similar solution.
        _serviceObjectWaitHandle.Set();
    }

    public void WaitForServiceObject()
    {
            //You may also expose other overloads, just for convenience.
            //This will wait until Store is executed
            //When _serviceObjectWaitHandle.Set() is called
            // this will let other threads pass.
            _serviceObjectWaitHandle.WaitOne();
    }

    public dynamic ServiceObject
    {
        get
        {
            return _serviceObject;
        }
    }
}

不过,我还没有涵盖所有的场景。实际上。。。如果多次调用GetConnection,会发生什么情况?我们需要决定是否允许这样做,如果允许,我们如何处理旧的serviceObject?(是吗