# RingBufferImage disposed automatically

**URL:** <https://forum.commonvisionblox.com/t/ringbufferimage-disposed-automatically/331>\
**Category:** .Net API\
**Tags:** ringbuffer, async\
**Created:** [January 10, 2018, 1:42pm UTC](https://forum.commonvisionblox.com/t/ringbufferimage-disposed-automatically/331 "2018-01-10T13:42:26Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![andrea.annovi](https://avatars.discourse-cdn.com/v4/letter/a/bc8723/32.png) [@andrea.annovi](https://forum.commonvisionblox.com/u/andrea.annovi)\
**Post date:** [January 10, 2018, 1:42pm UTC](https://forum.commonvisionblox.com/t/ringbufferimage-disposed-automatically/331/1 "2018-01-10T13:42:26Z")

</div>

I made a simple program that acquire data from a camera using the new .Net CVB library.  
I configured properly the device and I set the RingBufferLock Mode to ON.  
`device.Stream.RingBuffer.LockMode = RingBufferLockMode.On;`

If I understand correctly from the documentation every time I invoke `StreamImage image = await m_stream.WaitAsync()` it place the image acquired in the ring buffer and it locks the buffer for that specific image. It is up to me to unlock the image from the ringbuffer using`image.Unlock();`, in order to avoid to fill in completely the ringBuffer and don’t have enough space for new images.  
This behavior has been described also by @parsd in  
**IRingBuffer for Task-based Processing** “[Difference between Cvb.SharedImg and Cvb.Image.IMG](https://forum.commonvisionblox.com/t/difference-between-cvb-sharedimg-and-cvb-image-img/207/5)”  
“  
After you have your desired number of buffers, you can set the lock mode to RINGBUFFER\_LOCKMODE\_ON via the RBLockMode function. This is a manual mode in which the acquisition engine only locks the buffers to write-protect it for the engine. You as the user must unlock the buffer via RBUnlock when you don’t need it anymore. Otherwise no buffers are available anymore after the ring buffer is filled and no new images can be acquired.  
”

The strange thing is that after retrieving the image from the ring buffer in this way:  
`RingBufferImage image = m_stream.RingBuffer[lastAcquiredImageIndex];`  
and the RingBufferImage goes out of scope, it unlock automatically the slot in the buffer.

Am I doing something wrong?

I copy part of my code, in this way it should be more clear.

```auto
private Stream m_stream;

public void InitCamera()
{
	var device = LoadCameraDriver();
	device.Stream.RingBuffer.LockMode = RingBufferLockMode.On;
	device.Stream.RingBuffer?.ChangeCount(NUM_DRIVER_BUFFERS, DeviceUpdateMode.NewDeviceImage);

	m_stream = device.Stream;
}

public async Task AcquireData(CancellationTokenSource cts)
{
	m_stream.Start();

	while (!cts.Token.IsCancellationRequested)
	{
		using (StreamImage image = await m_stream.WaitAsync())
		{
			Tuple<IntPtr, int> res = GetBaseAddressAndBuffIndex(cts);
			var baseAddress = res.Item1;
			var buffIndex = res.Item2;
			var processingTask = Task.Run(async () => { await ProcessImage(baseAddress, buffIndex, imgTimeStamp, cts); });
			AddTask(PulseCounter, processingTask);
		}
	}

	List<Task> f = m_TaskDictionary.Values.ToList();
	Task.WaitAll(f.ToArray());
}

 private Tuple<IntPtr, int> GetBaseAddressAndBuffIndex(CancellationTokenSource cts)
{
	// last buffer acquired by G2Wait
	var lenght = m_stream.RingBuffer.GetAcquisitionSequence().Length;
	var lastAcquiredImageIndex = m_stream.RingBuffer.GetAcquisitionSequence()[lenght - 1];
	RingBufferImage image = m_stream.RingBuffer[lastAcquiredImageIndex];

	if (!image.IsLocked)
	{
		cts.Cancel();
		throw new ScannerException("Ring buffer image has not been locked.");
	}
	LinearAccessData imageData = image.Planes[0].GetLinearAccess();

	return new Tuple<IntPtr,int>(imageData.BasePtr, image.BufferIndex);
}

private async Task ProcessImage(IntPtr baseAddress, int buffIndex, long imgTimeStamp, CancellationTokenSource cts)
{
	RingBufferImage image = m_stream.RingBuffer[buffIndex];

	if (image.IsLocked)
	{
		// Do some stuff
		imageProcessed
		
		// dispose object
		image.Unlock();
		await Writer.WriteImageToFileAsync(imageProcessed);
	}
	else
	{
	   Console.WriteLine("Scanner: {0} - Ring buffer image has not been locked.Buffer Index: {1}", m_Name, buffIndex);
	}
}

```

When `GetBaseAddressAndBuffIndex` complete the execution, the ring buffer slot is Unlock automatically, and when I call the function `ProcessImage` the buffer is already unlock.  
I would expected the buffer being locked and not automatically unlocked by the .Net framework.

---

<div class="post-metadata">

**Author:** ![parsd](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/parsd/32/7_2.png) [@parsd](https://forum.commonvisionblox.com/u/parsd)\
**Post date:** [January 11, 2018, 5:41am UTC](https://forum.commonvisionblox.com/t/ringbufferimage-disposed-automatically/331/2 "2018-01-11T05:41:19Z")

</div>

Hi @andrea.annovi,

sorry, that will be again a bit longish 😇: first let me clear up a common misconception about the `IRingBuffer`:

> The _acquisition engine_ locks the `RingBufferImage`s, not the `Stream.Wait` methods.

In fact, the `Stream.Wait` methods `.Unlock()` the `RingBufferImage`s in `RingBufferLockMode.Auto` (the old image). The ring buffer is filled by the acquisition engine from another thread (not accessible to you). The `Stream.Wait` methods just let you sync to the next acquired image. Although this concept is implemented in :cvb: much longer than .Net’s `Task`s exist, you can imagine it as a combined call of `Task.Wait()` and `Task.Result`. The `Action` in the `Task` takes care of retrieving the correct buffer and doing the `.Unlock()` handling if needed.

#### Regarding the unlocked buffer

For `RingBufferImage`s `.Dispose()` is an alias of `.Unlock()`. This is like .Net’s [`Stream.Close()`](https://docs.microsoft.com/en-us/dotnet/api/system.io.stream.close?view=netframework-4.7.1#System_IO_Stream_Close) method. This is done as it is unsafe to access unlocked buffers (this can lead to very hard to debug bugs). In your code you run a processing task on a `RingBufferImage` that is scoped in a `using`-block. The scope exit of this block calls `.Dispose()` on it. As the processing task will very probably still run after the scope exit (or even start after it), you work on unlocked `RingBufferImage`s.

I suppose that is why you chose the more complex route to get the `RingBufferImage` from the `Stream.RingBuffer` instead of directly using the returned one from `.WaitAsync`. Via that you can still get unsafe access to the buffers.

For async processing you need to handle the `.Unlock()`ing manually:

```auto
public async Task StreamAnd(Action<RingBufferImage> action, CancellationToken token)
{
  m_stream.RingBuffer.LockMode = RingBufferLockMode.On;
  m_stream.Start();
  try
  {
    await AcquireImagesAnd(action, token);
  }
  finally
  {
    m_stream.Stop();
  }
}

private async Task AcquireImagesAnd(Action<RingBufferImage> action, CancellationToken token)
{
  var tasks = new List<Task>();

  while(!token.IsCancellationRequested)
  {
    var image = await m_stream.WaitAsync();
    tasks.Add(Task.Run(() => 
    {
      try
      {
        action(image);
      }
      finally
      {
        image.Unlock();
      }
    }));
  }

  await Task.WhenAll(tasks);
}

```

And combined with your processing:

```auto
var tcs = new CancellationTokenSource();
var processingTask = StreamAnd(image =>
{
  var imageData = image.Planes[0].GetLinearAccess();

  // process it

}, tcs.Token);

await Task.Delay(TimeSpan.FromSeconds(3));
tcs.Cancel();
await processingTask;

```

Everything in the action can be synchronous as it is run in the task pool anyways.

---

<div class="post-metadata">

**Author:** ![andrea.annovi](https://avatars.discourse-cdn.com/v4/letter/a/bc8723/32.png) [@andrea.annovi](https://forum.commonvisionblox.com/u/andrea.annovi)\
**Post date:** [January 11, 2018, 4:01pm UTC](https://forum.commonvisionblox.com/t/ringbufferimage-disposed-automatically/331/3 "2018-01-11T16:01:52Z")

</div>

Thank you, indeed the problem was in the RingBufferImage that is scoped in a using-block.

Now it works well.

Is there a way to retrieve the image ID of the acquired image (similar to the timestamp), using the new .Net API? I know it is possible with the C-API.

---

<div class="post-metadata">

**Author:** ![parsd](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/parsd/32/7_2.png) [@parsd](https://forum.commonvisionblox.com/u/parsd)\
**Post date:** [January 11, 2018, 4:04pm UTC](https://forum.commonvisionblox.com/t/ringbufferimage-disposed-automatically/331/4 "2018-01-11T16:04:59Z")

</div>

It should be in the `RingBufferImage.Tag`.

You can also combine the C-Api with the new .Net-Api: Just use the `Device.Handle` when you would have used the drivers’s `IMG`.
