Share via


Interlocked.Decrement Method (Int32%)

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Decrements a specified 32-bit signed integer variable and stores the result, as an atomic operation.

Namespace:  System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Syntax

'Declaration
Public Shared Function Decrement ( _
    ByRef location As Integer _
) As Integer
public static int Decrement(
    ref int location
)

Parameters

  • location
    Type: System.Int32%
    The variable whose value is to be decremented.

Return Value

Type: System.Int32
The decremented value.

Exceptions

Exception Condition
ArgumentNullException

The address of location is a null pointer.

Remarks

This method handles an overflow condition by wrapping: If location = Int32.MinValue, location - 1 = Int32.MaxValue. No exception is thrown.

Examples

The following example shows a thread-safe way to increment and decrement an integer value. The example defines CountClass, a class that keeps a running count of its instances by incrementing a counter in the constructor and decrementing the counter in the finalizer. Two counts are kept, one that uses standard addition and subtraction, and one that uses Increment and Decrement.

The example creates two threads, each of which creates and releases a large number of CountClass instances. After a garbage collection has been forced to clean up all the instances, both counts should be zero. SafeInstanceCount, which uses the Interlocked methods, will always be zero. However, UnsafeInstanceCount will not necessarily be zero because addition and subtraction are not atomic on fields: The count must be fetched, incremented, and then stored. A thread can be preempted in the middle of the increment or decrement operation — for example, after it has loaded and incremented the count, but before the new value has been stored. While the thread is preempted, the other thread can increment the count, or the finalizer thread can decrement the count. When the first thread continues running and stores its new value, it wipes out the operations that occurred while it was preempted. This program magnifies that effect because it does nothing but create instances, so that many instances of CountClass could be created while a thread is preempted.

In addition, on a multiprocessor computer two threads can be performing an operation simultaneously. Both can fetch the same value, increment it, and store it, so that the count is increased by one even though two instances are created.

Imports System.Threading

Public Class Example

   Private Shared outputBlock As System.Windows.Controls.TextBlock

   Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

      Example.outputBlock = outputBlock
      Dim t As New Thread(AddressOf DemoThreadProc)
      t.Start()

   End Sub

   Private Shared Sub DemoThreadProc()

      ' Start two threads that will create/destroy a large number of CountClass
      ' objects, and block until the thread finish.
      Dim thread1 As New Thread(AddressOf ThreadMethod)
      Dim thread2 As New Thread(AddressOf ThreadMethod)
      thread1.Start()
      thread2.Start()
      thread1.Join()
      thread2.Join()

      ' Have the garbage collector run the finalizer for each
      ' instance of CountClass and wait for it to finish.
      GC.Collect()
      GC.WaitForPendingFinalizers()

      outputBlock.Dispatcher.BeginInvoke(displayHelper, _
          String.Format( _
             "After garbage collection has occurred for all instances of CountClass," & vbLf _
                 & "the instance count should be zero." & vbLf & vbLf _
                 & "UnsafeInstanceCount: {0}" & vbLf & "SafeInstanceCount: {1}", _
                        CountClass.UnsafeInstanceCount, _
                        CountClass.SafeInstanceCount))
   End Sub

   Private Shared Sub ThreadMethod()
      Dim cClass As CountClass

      ' Create 100,000 instances of CountClass.
      For i As Integer = 1 To 100000
         cClass = New CountClass()
      Next i
   End Sub

   ' Helper methods:

   ' In order to update the TextBlock object, which is on the UI thread, you must
   ' make a cross-thread call by using the Dispatcher object that is associated 
   ' with the TextBlock. The DisplayOutput helper method and its delegate, 
   ' displayHelper, are used by the BeginInvoke method of the Dispatcher object
   ' to append text to the TextBlock. 
   '
   Private Shared displayHelper As New Action(Of String)(AddressOf DisplayOutput)
   Private Shared Sub DisplayOutput(ByVal msg As String)
      outputBlock.Text &= msg 
   End Sub

End Class

Public Class CountClass

   Shared unsafeCount As Integer = 0
   Shared safeCount As Integer = 0

   Shared ReadOnly Property UnsafeInstanceCount() As Integer
      Get
         Return unsafeCount
      End Get
   End Property

   Shared ReadOnly Property SafeInstanceCount() As Integer
      Get
         Return safeCount
      End Get
   End Property

   Sub New()
      unsafeCount += 1
      Interlocked.Increment(safeCount)
   End Sub

   Protected Overrides Sub Finalize()
      unsafeCount -= 1
      Interlocked.Decrement(safeCount)
      MyBase.Finalize()
   End Sub

End Class

' This example produces output similar to the following:
'
'After garbage collection has occurred for all instances of CountClass,
'the instance count should be zero.
'
'UnsafeInstanceCount: -305
'SafeInstanceCount: 0
using System;
using System.Threading;

class Example
{
   private static System.Windows.Controls.TextBlock outputBlock;


   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Example.outputBlock = outputBlock;
      Thread t = new Thread(DemoThreadProc);
      t.Start();
   }

   private static void DemoThreadProc()
   {
      // Start two threads that will create/destroy a large number of CountClass
      // objects, and block until the thread finish.
      Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
      Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
      thread1.Start();
      thread2.Start();
      thread1.Join();
      thread2.Join();

      // Have the garbage collector run the finalizer for each
      // instance of CountClass and wait for it to finish.
      GC.Collect();
      GC.WaitForPendingFinalizers();

      outputBlock.Dispatcher.BeginInvoke(delegate () {
          outputBlock.Text += String.Format(
             "After garbage collection has occurred for all instances of CountClass,\n" 
                 + "the instance count should be zero.\n\n" 
                 + "UnsafeInstanceCount: {0}\nSafeInstanceCount: {1}\n",
                        CountClass.UnsafeInstanceCount, 
                        CountClass.SafeInstanceCount); 
                                                     });
   }

   static void ThreadMethod()
   {
      CountClass cClass;

      // Create 100,000 instances of CountClass.
      for (int i = 0; i < 100000; i++)
      {
         cClass = new CountClass();
      }
   }
}

class CountClass
{
   static int unsafeInstanceCount = 0;
   static int safeInstanceCount = 0;

   static public int UnsafeInstanceCount
   {
      get { return unsafeInstanceCount; }
   }

   static public int SafeInstanceCount
   {
      get { return safeInstanceCount; }
   }

   public CountClass()
   {
      unsafeInstanceCount++;
      Interlocked.Increment(ref safeInstanceCount);
   }

   ~CountClass()
   {
      unsafeInstanceCount--;
      Interlocked.Decrement(ref safeInstanceCount);
   }
}

/* This example produces output similar to the following:

After garbage collection has occurred for all instances of CountClass,
the instance count should be zero.

UnsafeInstanceCount: -292
SafeInstanceCount: 0
 */

Version Information

Silverlight

Supported in: 5, 4, 3

Silverlight for Windows Phone

Supported in: Windows Phone OS 7.1, Windows Phone OS 7.0

XNA Framework

Supported in: Xbox 360, Windows Phone OS 7.0

Platforms

For a list of the operating systems and browsers that are supported by Silverlight, see Supported Operating Systems and Browsers.