如何在 C# 中取消引用对象

本文关键字:取消 引用 对象 | 更新日期: 2023-09-27 18:31:38

我有一个在两个索引之间循环的缓冲区,我想在任务中的当前索引处写出对象,并允许程序的其余部分继续处理内容。我试图简化流程,同时保留所有相关部分。

    object[] buffer = new object[2]
    int currentIndex = 0
    while(true){
        buffer[currentIndex].field1 = newdatahere //data grabbed by sensor bundle
        buffer[currentIndex].field2 = newdatahere //data grabbed by camera bundle
        buffer[currentIndex].field3 = newdatahere //data grabbed from system snapshot
        task.factory.starnew(()=>{
            writeOutObject(buffer[currentIndex])
        }
        buffer[currentIndex] = new object();
        currentIndex = 1 - currentIndex //cycle between the 0 and 1 indices
    }
    void writeOutObject(Object obj){
        //do file IO here
        //write out field1, field2, field3
    }

问题是,通过将缓冲区项分配给新对象,我正在杀死 writeOutObject 方法,因为在任务运行时 obj 不再存在。我希望能够保留旧对象,直到它被写出并具有新对象的缓冲区点。

我想做什么:

    object obj1 = new object();
    obj1.field1 = data1;
    obj1.field2 = data2;
    obj1.field3 = data3;
    obj2 = obj1;
    //de-reference obj1 from the object that it was pointed to and associate it to a new object
    // i want this to write out data1,data2,data3 but instead it is 
    // writing out data4,data5,data6 or some mixture because it has 
    // been overwritten halfway through the file IO
    task.factory.startnew(()=>{ write out obj2 } 
    obj1.field1 = data4;
    obj1.field2 = data5;
    obj1.field3 = data6;

也许像这样:

    obj1 = new object()
    obj2* = &obj1
    obj1* = &new object

分配后,我需要将 obj1 的引用分解回 obj2。简单地这样做是行不通的:

    obj1 = new object()
    obj2 = obj1
    obj1 = null // or new object()

根据要求,"真正的代码"

    CancellationTokenSource cts = new CancellationTokenSource();
    public void StartMachine()
    {
        Task.Factory.StartNew(() =>
            {
                _isFirstData = true;
                _expiredFlag = false;
                Plc.StartPLC();
                Plc.Start();
                while (true)
                {
                    if (!_paused && !Plc.IsInputStackEmpty() && !Plc.IsOutputSlideOpen())
                    {
                        CameraFront.SnapAquire();
                        // If this is the first data set the wait handles
                        if (!_isFirstData)
                        {
                            CameraBack.SnapAquire();
                        }
                        else
                        {
                            _imageBackRecieved.Set();
                            _databaseInfoRecieved.Set();
                            //_isFirstCard = false;
                        }
                        // Wait for 3 things! Image Front, Image Back, Database
                        bool gotEvents = WaitHandle.WaitAll(_waitHandles, TIMEOUT);
                        if (gotEvents)
                        {
                            if (!_isFirstData)
                            {
                                if (Buffer[1 - NextDataOutIndex].IsDataComplete())
                                {
                                    if (Buffer[1 - NextDataOutIndex].EvaluateData()) 
                                    {
                                        OnPassFailNotification()
                                        Plc.Pass();
                                    }
                                    else
                                    {
                                        OnPassFailNotification()
                                        Plc.Fail();
                                    }
                                }
                                else
                                {
                                    OnPassFailNotification()
                                    Plc.Fail();
                                    Common.Logging
                                }
                            }
                            else
                            {
                                _isFirstData = false;
                            }
                        }
                        else
                        {
                           Common.Logging("WARNING: Wait handle timed out"
                            Plc.Fail();
                        }
                        Data temp = Buffer[1 - NextDataOutIndex];
                        Task.Factory.Startnew(()=>{
                            Data.WriteData(temp);
                        }
                        Buffer[1 - NextDataOutIndex] = new Data(); 
                        // Swap card buffers - alternate between 1 and 0
                        NextdataOutIndex = 1 - NextDataOutIndex;
                        // Do this
                        Plc.WheelAdvance();
                    }
                    else
                    {
                    }
                }
            }, cts.Token);                
    }

    public static void WriteData(Data data)
    {
        if(WRITE_BATCH_FILES)
        try
        {
            if (data.ImageFront != null)
            {
                string filenameforfront = "blahlbah-front.tiff";
                OperatorSet.WriteImage(data.ImageFront, "tiff", 0, filenameforfront);
            }
            if (data.ImageBack != null)
            {
                string filenameforback = "blahblah-back.tiff";
                HOperatorSet.WriteImage(data.ImageBack, "tiff", 0, filenameforback);
            }
        }
        catch (Exception ex)
        {
            Common.Logging.
            //throw ex;
        }
        //TODO: Write out data in xml
        //TODO: Write out metrics
    }

如何在 C# 中取消引用对象

在你 task.factory.StartNew 之前执行以下操作

while(...)
{
   ... bunch of other code
   buildTask(buffer[currentIndex]);
   buffer[currentIndex] = new object();
   ... bunch of other code
}
// Within this method, all references to detachedBuffer object will remain pointing to the same
// memory location no matter whether the variable passed in is reassigned.
public void buildTask(object detachedBuffer)
{
    task.factory.starnew(()=>{
        writeOutObject(detachedBuffer);
    };
}

听起来像是信号量的工作!信号量是一种线程间通信形式,非常适合这种情况,因为它们允许一个线程锁定信号量,但另一个线程再次释放信号量。在下面的代码示例中,sem.WaitOne()行将等待调用sem.Release()方法。这会阻止您的主线程足够长的时间,以便您的任务获得所需的数据。

object[] buffer = new object[2]
int currentIndex = 0
while(true){
    buffer(currentIndex).field1 = newdatahere //data grabbed by sensor bundle
    buffer(currentIndex).field2 = newdatahere //data grabbed by camera bundle
    buffer(currentIndex).field3 = newdatahere //data grabbed from system snapshot
    Semaphore sem = new Semaphore(1,1);  //Initialise the semaphore so that it is checked out
    task.factory.starnew(()=>{
        object item = buffer[currentIndex]; //Create local reference to the data item
        sem.Release(); //Check-in the semaphore (let the WaitOne method return)
        writeOutObject(item)
    }
    sem.WaitOne(); //Block until the semaphore has returned
    buffer[currentIndex] = new object();
    currentIndex = 1 - currentIndex //cycle between the 0 and 1 indices
}
void writeOutObject(Object obj){
    //do file IO here
    //write out field1, field2, field3
}