• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 220
  • Last Modified:

2 threads updating one object

i have 2 threads one updates a dataset so information on a primary gridview can be updated and viewed while other data loading occurs.
the 2nd thread updates the same dataset so that information on a secondary gridview is loaded. the problem is that the while loop in the threads skips out updating the dataset. will loop (like) 9 times with out actually updating the ds.

we are grabing information from a wcf service using paging fill.  and to get the bindings to controls to stay we have to pass it a temporary ds by ref and then merge that into the forms base dataset. everytime we loop we clear the pertinent datatable in the temporary ds to get ready for a new page of data. this seems to be the issue. sometimes the threads while loop will go back through and hit that before the merge actually occurs, thereby erasing the data that we need to proceed.

hopefully someone can help, and i know that this hasn't been explained the best so let me know what you need.
0
p_davis
Asked:
p_davis
  • 9
  • 5
1 Solution
 
evilrixSenior Software Engineer (Avast)Commented:
0
 
evilrixSenior Software Engineer (Avast)Commented:
The code below is a working example of how a mutex synchronizes threads. Without it the output is a mess. With it each thread outputs 10 lines and then defers to the other. To see the difference comment out the bits I've noted in the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
 
 
namespace cs_console
{
    class Program
    {
        static bool bQuit = false;
        static Mutex mtx = new Mutex(false);
 
        static void ThreadFunc()
        {
            while (!bQuit)
            {
                for (int x = 0; x < 10; ++x)
                {
                    //////////////////////////////////////////////////
                    // Comment out to see what it's like with no mutex
                    mtx.WaitOne();
                    //////////////////////////////////////////////////
                    for (int y = 0; y < 10; ++y)
                    {
                        Console.WriteLine("In thread: " + y.ToString());
                        Thread.Sleep(0);
                    }
                    //////////////////////////////////////////////////
                    // Comment out to see what it's like with no mutex
                    mtx.ReleaseMutex();
                    //////////////////////////////////////////////////
                }
            }
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(new ThreadStart(Program.ThreadFunc));
            thread.Start();
 
            for (int x = 0; x < 10; ++x)
            {
                //////////////////////////////////////////////////
                // Comment out to see what it's like with no mutex
                mtx.WaitOne();
                //////////////////////////////////////////////////
                for (int y = 0; y < 10; ++y)
                {
                    Console.WriteLine("In main: " + y.ToString());
                    Thread.Sleep(0);
                }
                //////////////////////////////////////////////////
                // Comment out to see what it's like with no mutex
                mtx.ReleaseMutex();
                //////////////////////////////////////////////////
            }
 
            bQuit = true;
 
            thread.Join();
        }
    }
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
If you just want one thread to signal the other thread when to clear the ds, consider using an AutoResetEvent: -

http://msdn2.microsoft.com/en-us/library/system.threading.autoresetevent.aspx

0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

 
p_davisAuthor Commented:
thanks for the ideas i will try. i had been messing with locks and monitor but nothing seemed to work the way i thought it should.

should the mutex calls be wrapped in a try/finally block so the release always gets called?
0
 
evilrixSenior Software Engineer (Avast)Commented:
The following example uses 2 auto reset events to pass signals between main and thread. Comments in the code should clarify what is going on: -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
 
 
namespace cs_console
{
    class Program
    {
        static bool bQuit = false;
        static Mutex mtx = new Mutex(false);
        static AutoResetEvent autoEventThread = new AutoResetEvent(false);
        static AutoResetEvent autoEventMain = new AutoResetEvent(false);
 
        static void ThreadFunc()
        {
            while (!bQuit)
            {
                for (int x = 0; x < 10; ++x)
                {
                    //////////////////////////////////////////////////////
                    // Wait for main to signal
                    autoEventThread.WaitOne();
                    //////////////////////////////////////////////////////
 
                    if (!bQuit)
                    {
                        //////////////////////////////////////////////////
                        // Comment out to see what it's like with no mutex
                        mtx.WaitOne();
                        //////////////////////////////////////////////////
                        for (int y = 0; y < 10; ++y)
                        {
                            Console.WriteLine("In thread: " + y.ToString());
                            Thread.Sleep(0);
                        }
                        //////////////////////////////////////////////////
                        // Comment out to see what it's like with no mutex
                        mtx.ReleaseMutex();
                        //////////////////////////////////////////////////
                        // Signal main
                        autoEventMain.Set();
                        //////////////////////////////////////////////////
                    }
                }
            }
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(new ThreadStart(Program.ThreadFunc));
            thread.Start();
 
            for (int x = 0; x < 10; ++x)
            {
                //////////////////////////////////////////////////
                // Use event to ensure main runs before thread
                // and do two main loops to one thread loop
                if ((x > 0) && (x % 2) == 0)
                {
                    // Signal thread
                    autoEventThread.Set();
                    // Wait for thread to signal
                    autoEventMain.WaitOne();
                }
                //////////////////////////////////////////////////
                // Comment out to see what it's like with no mutex
                mtx.WaitOne();
                //////////////////////////////////////////////////
                for (int y = 0; y < 10; ++y)
                {
                    Console.WriteLine("In main: " + y.ToString());
                    Thread.Sleep(0);
                }
                //////////////////////////////////////////////////
                // Comment out to see what it's like with no mutex
                mtx.ReleaseMutex();
                //////////////////////////////////////////////////
            }
 
            bQuit = true;
 
            //////////////////////////////////////////////////////
            // Signal thread
            autoEventThread.Set();
            //////////////////////////////////////////////////////
 
            thread.Join();
        }
    }
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
>> should the mutex calls be wrapped in a try/finally block so the release always gets called?
You need to ensure your code is exception safe. I've left that out for clarity.
0
 
p_davisAuthor Commented:
ok, that seems to work better but it also seems creates a problem that i saw earlier

after loading the data i have to sort the primary grid so the data shows (otherwise it is just blank)
0
 
p_davisAuthor Commented:
meaning i have to manually click on the column header on the grid that is on the  ui.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> ok, that seems to work better but it also seems creates a problem that i saw earlier
Creates or shows up existing?
0
 
p_davisAuthor Commented:
before the way i was doing it it would load after a certain amount of time but it would loop through with the clearing the datatable several times and then it would go through.
you could see the data actively being loaded into both gridviews but now you can't until you click on the column header

>>Creates or shows up existing?
i guess it could be debatable, but i'm hoping we won't as i would like to know how to correct this
0
 
evilrixSenior Software Engineer (Avast)Commented:
Using try/finally to ensure code is exception safe...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
 
 
namespace cs_console
{
    class Program
    {
        static bool bQuit = false;
        static Mutex mtx = new Mutex(false);
 
        static void ThreadFunc()
        {
            while (!bQuit)
            {
                for (int x = 0; x < 10; ++x)
                {
                    if (!bQuit)
                    {
                        try
                        {
                            //////////////////////////////////////////////////
                            // Comment out to see what it's like with no mutex
                            mtx.WaitOne();
                            //////////////////////////////////////////////////
                            for (int y = 0; y < 10; ++y)
                            {
                                Console.WriteLine("In thread: " + y.ToString());
                                Thread.Sleep(0);
                            }
                            //////////////////////////////////////////////////
                        }
                        finally
                        {
                            //////////////////////////////////////////////////
                            // Comment out to see what it's like with no mutex
                            mtx.ReleaseMutex();
                            //////////////////////////////////////////////////
                        }
                    }
                }
            }
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(new ThreadStart(Program.ThreadFunc));
            thread.Start();
 
            for (int x = 0; x < 10; ++x)
            {
                try
                {
                    //////////////////////////////////////////////////
                    // Comment out to see what it's like with no mutex
                    mtx.WaitOne();
                    //////////////////////////////////////////////////
                    for (int y = 0; y < 10; ++y)
                    {
                        Console.WriteLine("In main: " + y.ToString());
                        Thread.Sleep(0);
                    }
                    //////////////////////////////////////////////////
                }
                finally
                {
                    //////////////////////////////////////////////////
                    // Comment out to see what it's like with no mutex
                    mtx.ReleaseMutex();
                    //////////////////////////////////////////////////
                }
            }
 
            bQuit = true;
 
            thread.Join();
        }
    }
} 

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
>> i guess it could be debatable, but i'm hoping we won't as i would like to know how to correct this
Well, I think it's fair to say it's probably an existing issue that has now manifested due to introduction of synchronization. I'm not sure I can help you out with that. I think you'll need to do a little debugging unfortunately.
0
 
p_davisAuthor Commented:
no matter, thank you for your posts.  the last part-- all i did was reset the bindings on the bindingsource and the data loaded fine.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> all i did was reset the bindings on the bindingsource and the data loaded fine.
Great, I'm glad you figured that out. That kind of stuff -- not my strength :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

  • 9
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now