Page 1 of 1

Unmanaged Code, Pointers, and GC

#1 sk8ermeb  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 20
  • View blog
  • Posts: 111
  • Joined: 23-March 10

Posted 27 January 2011 - 11:28 AM

Welcome to my tutorial on pointers in C#. I have decided to spend the time to write this because of the lack of information I could find on the internet and so I had to learn after a lot of trial and error.

The reader should know that pointers are advised against, and should only be used if absolutely necessary for reasons I will talk about.

What are Pointers?
Pointers are a type of variable, that instead of holding the actual data, they hold the memory location to specific data. The extra coding power this gives you also can be dangerous.

Why would I need a pointer?
Pointers allow different parts of your software to work off the same variable in memory. This means that for time sensitive data, as soon as the variable is altered, any other part of your code has access to the new value. One example that forced me to learn about pointers was communicating with several pieces of hardware over interrupts, in which they all needed the same information in nearly real time. This was nearly impossible without pointers

You do not need pointers to get multiple returns in C#. This can be accomplished with the "ref" keyword which will be discussed.

Managed code
Any time you are writing code, you are writing "managed" code, which is managed by the Common Language Runtime(CLR). The CLR keeps track of what memory is being used, so the programmer does not have to. This is why C# and java, in my opinion, are easier than C. Because of the CLR hides everything it is doing, the user has no guarantee where in memory a variable might be, therefore in order to use a pointer we need to write what is called un-managed code.

Any time you do anything with pointers you need to designate it by the keyword "unsafe". This tells the compiler to exclude this from the CLR and is there for un managed.
In order to compile code with the "unsafe" keyword you need to set allow unsafe code

This means that you have the responsibility of doing Garbage Cleanup, or de-allocating the memory.
An example of using the unsafe keyword is
private void MyMethod()
{
  unsafe
  {

  }
}


The unsafe keyword can also go before a method class or variable to designate that all the following code is unsafe.
unsafe class MyClass
{

}


or
unsafe class MyClass
{

}


or
unsafe private void MyMethod()
{

}


When you are declaring a pointer of any type the keyword unsafe needs to be placed
private unsafe int* variablePointer


notice the "*". This means that the variable "variablePointer" contains a memory address to and int, and does not actually contain an integer.
To declare multiple pointers in one line use:
private unsafe int* variablePointer1, variablePointer2, variablePointer3



One thing you should know is that pointers are not objects in c# therefore do not inherit any object methods such as .Equals(obj);
you can also make an array of pointers such as
unsafe int*[] p;


which will make an array of pointers that all point to integers.

Now since the reason you use pointers is to have the same variable be accessed in multiple places, we need to learn to "pin" the memory location of a variable so that we can get its address. Again this needs to be used within unsafe scope:
int theVariable = 5;
unsafe
{
 fixed(int* tempPointer = &theVariable)
 {
   //writes out "5"
   Console.WriteLine(*tempPointer);

   //writes out some long integer that is
  //the memory location of theVariable
   Console.WriteLine((int)tempPointer);
 }
}


In the fixed statement the variable on the right is being fixed because it is on the right of the fixed() clause.
The "&" before a variable returns the memory location of that variable. In C# all pointers are automatically fixed since the CPL will not touch them.
Console.WriteLine(*tempPointer);
using the * de-references the variable so that instead of returning what tempPointer actually contains, which is the memory address returned by &theVariable, it knows to return the integer found at the address held in "tempPointer". I hope that makes since. On the other hand simply casting whatever is found at tempPointer to an int we can print out the what the real memory location is of &theVariable.
Now the variables memory location only stays fixed as long as its within fixed{ } brackets. This doesn't mean we cant still use our pointer, it just means that we are not guaranteed that
theVariable will have the same value as *tempPointer.

The final thing we have to talk about before we go through an example is the keyword "ref". This keyword is used as a pointer, only in passing a variable into a constructor or a method. In most cases this will allow us to get away without actually using pointers since this keyword acts just like one but still operates within the CLR. for example:
int i=7;
MyMethod(ref i);
Console.WriteLine(i); //7

public void MyMethod(ref int i)
{
   i+=3;
}


Notice that the keyword unsafe is never used

Lets actually go through a complete example where we illustrate this. This example will run an infinite loop so we prepared to stop debugging with your IDE. In VS it is "Shift+F5" Also

1 Create a new "Console Application" called "PointerTest"
2 Set allow unsafe code. By editing the properties of your project
We will need 3 classes in order to illustrate the idea. The reason is that variables created in the main entry function are automatically fixed until the program ends, however in a program that is complex, it is in bad practice to write everything into the main function, therefore we need to create two other layers of classes to illustrate these points.

The first class is the MainClass
using System;
using System.Windows.Forms;

namespace PointerTest
{
	class MainClass
	{	
		static void Main(string[] args)
		{	
			Worker W = new Worker();
			Application.Run(W);
		}		
	}
}



The next Class is the Worker Class

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace PointerTest 
{
 class Worker : Form
 {
  private Label varLabel;
  private int variable;
  private Thread updateThread;
  Operator[] op;

  public Worker()
  {
   this.Closed+=new EventHandler(Worker_Closed);
   variable = 100;
   varLabel = new Label();
   Controls.Add(varLabel);
   updateThread = new Thread(new ThreadStart(this.updateLabel));
   updateThread.Start();
   op = new Operator[20];
   op[0] = new Operator(-4, 500, ref variable);
   op[1] = new Operator(2, 700, ref variable);
   op[2] = new Operator(6, 800, ref variable);
   op[3] = new Operator(-1, 200, ref variable);			
		
   }
  unsafe private void updateLabel()
  {
   //fixed(int* varr = &variable)
   //{
    do
    {
     this.varLabel.Text = this.variable.ToString();
     Thread.Sleep(20);			
    }while(true);
   //}
  }
  protected override void onkeypress(KeyPressEventArgs e)
  {
   base.onkeypress (e);
   this.variable+=e.KeyChar;			
  }
  public void Worker_Closed(Object who, EventArgs e)
  {
   updateThread.Abort();
  }

 }
}



And the final class is

using System;
using System.Threading;

namespace PointerTest
{
 class Operator
 {
  private int incValue, period;
  private unsafe int* variablePointer;
  private Thread runThread;
  private int temp;
		
  public Operator(int incrementValue, int itterationPeriod, ref int theVariable)
  {
   incValue = incrementValue;
   period = itterationPeriod;
   unsafe
   {
    fixed(int* tempPointer = &theVariable)
    {
     this.variablePointer = tempPointer;					
    }
   }			
   runThread = new Thread(new ThreadStart(run));
   runThread.Start();
  }
  public void run()
  {			
    do
    {
     unsafe {temp = *variablePointer;}
     temp+=incValue;
     unsafe{*variablePointer = temp;}
     Console.WriteLine(temp.ToString());
     Thread.Sleep(period);
    }while(true);			
  }
  ~Operator()
  {			
  }
 }
}



Now when you run this code you should notice that after a certain amount of time the form and the console are reporting different numbers. This is because the original "variable" in worker has changed memory locations because its position in memory was only pinned during the "fixed" where the pointer was getting its memory location. If the form is the active screen and you press a key to add a value you will notice the two numbers are acting like completely different variables. The pointer is still pointing to the same memory location, but the variable has changed locations, since all pointers are always fixed.

In order to fix this problem simply un comment out the
//fixed(int* varr = &variable)
//{
//}



Since this is an infinite loop, "variable" will always remain fixed because for the entire time you are running the program there is code operating within the fixed statement that fixes the variable. Until we are outside these fixed brackets we are guaranteed that the memory location will remained pinned. Sometimes you simply need to keep a variable fixed arbitrarily for a certain amount of time. One thing you can do is Suspend() a thread that is inside a fixed statement until itís no longer needed then Resume() that way you donít burn up a necessary processor power.

Responsibilities when running unsafe code
Before you begin writing a lot of code that is unsafe you should do some reading on the Garbage collection system at the MSDN website. Bottom line is:
Any object that is used within unsafe code at any time that has a Dispose() method should have the Dispose() method called in the destructor

first you will notice that the Operator class's destructor is blank.
 ~Operator()
  {			
  }



This is because that class was carefully written so that the unsafe did not encompass any objects that were managed by the Garbage Collection(GC).
However there is a problem in the Worker class. The fixed statement that we uncommented to ensure that the original variable stay pinned is a label which is an object. This means that we are not guaranteed that the GC will de allocate the memory. The destructor needs to be added to this class. Add the following code to the bottom of the Worker class:
~Worker()
{
 this.varLabel.Dispose();
}



If you add a method to the Disposed event handler you will notice that even without this it does actually get disposed of in this case. Not to add unnecessary confusion, but this is because the GC tries its best to take care of things, and I think this actually has to do with the fact that we are using the form thread Application.Run(), but the point is that we are not guaranteed this, especially if you are working with objects that are declared unsafe the best rule of thumb is to manually call all dispose methods.

Two more things to note. One is that the temp variable in the operator class maybe changing memory locations, but no pointers are dependant upon this. The pointer each time retrieves it value from the temp variable. If we wanted to have the pointer automatically pointing to temp we would have to pin down temp as well.
Next variables are automatically fixed if declared within a method, because the GC knows exactly when the variable will no longer be needed, after the closing brackets. If you want to do some more reading, read information on the "using" keyword. This can be used to tell the GC when you will be using the variable so it can fix it.

Also you can pass pointers into a constructor or method instead of using ref, but this is always in bad practice because we need to call or declare our class within the unsafe context, and the goal is to minimize the amount of code that unsafe encompasses.

Last thing, MSDN says NEVER use pointers within a web server. If you want to know why you can look it up.

Is This A Good Question/Topic? 2
  • +

Page 1 of 1