Search code examples
wpfmultithreadingpcap.net

Class member behave differently when define as static or non static


I have WPF application with PcapDotNet DLL's that measure my machine Interface Rate.

This is the Model:

public class Interface
{
    public PacketDevice PacketDevice { get { return livePacketDevice; } }
    private DateTime _lastTimestamp;
    private double _bitsPerSecond;
    private double _packetsPerSecond;
    private DateTime _lastTimestamp;
    private static List<Interface> _machineInterfaces; // list of all machine interfaces

    public void Start(Interface inf)
    {
        OpenAdapterForStatistics(inf.PacketDevice);
    }

    public void OpenAdapterForStatistics(PacketDevice selectedOutputDevice)
    {
        if (selectedOutputDevice != null)
        {
            using (PacketCommunicator statCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the output adapter
            {
                try
                {
                    statCommunicator.Mode = PacketCommunicatorMode.Statistics; //put the interface in statstics mode
                    statCommunicator.ReceiveStatistics(0, StatisticsHandler); //start the main loop
                }
                catch (Exception)
                { }
            }
        }
    }

    private void StatisticsHandler(PacketSampleStatistics statistics)
    {
        DateTime currentTimestamp = statistics.Timestamp; //current sample time
        DateTime previousTimestamp = _lastTimestamp; //previous sample time
        _lastTimestamp = currentTimestamp; //set _lastTimestamp for the next iteration

        if (previousTimestamp == DateTime.MinValue) //if there wasn't a previous sample than skip this iteration (it's the first iteration)
            return;

        double delayInSeconds = (currentTimestamp - previousTimestamp).TotalSeconds; //calculate the delay from the last sample
        _bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
        _packetsPerSecond = statistics.AcceptedPackets / delayInSeconds; //calculate packets per second

        if (NewPointEventHandler != null)
            NewPointEventHandler(_bitsPerSecond);
        double value = _packetsPerSecond;
    }

As you can see Start method start to measure the Interface rate and put the values into 2 fields:

_bitsPerSecond and _packetsPerSecond.

So after the application start i have this field:

List<Interface> _machineInterfaces; 

That read all my machine interfaces.

After that i start my Start method:

    private void StartStatistics()
    {
        int index = listview.SelectedIndex; // select the selected interface from my `ListView` list.
        Interface inf = new Interface();
        ThreadStart tStarter = delegate
        {              
            inf.Start(Interface.MachineInterfaces[index]); // send the selected interface
        };
        Thread thread = new Thread(tStarter);
        thread.IsBackground = true;
        thread.Start();

        statisticsTimer.Start(); // start my timer
    }
  • OK so now this is my Question:

This is my Timer Tick Event:

public RadObservableCollection<double> mbitPerSecondValue { get; private set; }

If my BitsPerSecond Class Interface member define as regular and not Static it's value is always zero:

    private void statisticsTimer_Tick(object sender, EventArgs e)
    {
        int index = listview.SelectedIndex;

        double bps = Interface.MachineInterfaces[index].BitsPerSecond; // always zero !
        mbitPerSecondValue.Add(bps);
    }

In case BitsPerSecond define as static all good:

    private void statisticsTimer_Tick(object sender, EventArgs e)
    {
        int index = listview.SelectedIndex;
        double bps = Interface.BitsPerSecond;
        mbitPerSecondValue.Add(bps);
    }

So my question is why ?

Edit

Currently i changed my function:

private void StartStatistics()
        {
            int index = lvAdapters.SelectedIndex;
            Interface inf = new Interface();
            ThreadStart tStarter = delegate
            {
                foreach (Interface item in Interface.MachineInterfaces)
                    item.Start();
            };

            Thread thread = new Thread(tStarter);
            thread.IsBackground = true;
            thread.Start();

            statisticsTimer.Start();
        }

What i want to achieve is to open statistics on each interface on my machine , but again in the first interface (i have 2) i can see the traffic changing (BitsPerSecond) but in the second interface it's always zero (i make sure to generate some traffic through this interface so it not supposed to be zero)


Solution

  • For your second question, try to call each Interface's Start from different threads. The only suspicious thing I see is that maybe statCommunicator.ReceiveStatistics is blocking the thread and preventing the other Interfaces from being Started.

    This should avoid that problem:

    private void StartStatistics()
    {
        foreach (Interface item in Interface.MachineInterfaces)
        {
            ThreadStart tStarter = delegate
            {
                item.Start();
            };
    
            Thread thread = new Thread(tStarter);
            thread.IsBackground = true;
            thread.Start();
        }
    
        statisticsTimer.Start();
    }