我有一个在两个索引之间循环的缓冲区,我想在任务中写出当前索引处的对象,并允许程序的其余部分继续处理。我试图在保持所有相关部分的同时简化过程。
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
}
答案 0 :(得分:2)
执行以下操作
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);
};
}
答案 1 :(得分:0)
听起来像Semaphores的工作!
信号量是线程间通信的一种形式,对于这种情况是理想的,因为它们允许一个线程锁定信号量而另一个线程再次释放信号量。在下面的代码示例中,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
}