i have a background worker with a sleep method inside a method. (winforms)

here is the code that is executed:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            int[] makeSelfMoves = new int[4];

            foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
            {
                makeSelfMoves = replay[item.Key];// the Dictionary contains all the chess moves, rowStart,columnStart,rowEnd,columnEnd
                codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);// this method executes the code.
                PrintPieces(codeFile.PieceState());              
                System.Threading.Thread.Sleep(1000);
            }
            //PrintPieces(codeFile.FirstTimeLoad());
            //PrintPieces(codeFile.PieceState());

        }

it is being activated by an outside method.

public void ReplayGame()
        {
            Class2.replayIsOn = true;
            replay=serializeMeh.giveBackDictionary();


            if (backgroundWorker1.IsBusy != true)
            {
                // Start the asynchronous operation.
                backgroundWorker1.RunWorkerAsync();
            }

i tested the code many times with a messagebox, it works. but when i put it inside a that backgroundworker, what happens, is synchronization problems, if i activated the method ReplayGame once, it works, fine, but the more i activate it, the more synchronization problems there are. for example, the replay may stagger, lag in the middle of the game and then continue... or freeze!!

Recommended Answers

All 11 Replies

In your BackgroundWorker you are accessing a collection in a Thread unsafe manor. You need to lock replay during the entire process or you'll have issues if something else accesses it. Does codeFile.ExecuteAll make changes to replay?

no, ReplayGame, is the only function in the winform, it can only be triggered by an event in the menuStrip... executeAll(). is a method in a different class in a different file, it is in the logic code file.

Here is what triggers ReplayGame:

private void replayToolStripMenuItem_Click(object sender, EventArgs e)
        {
      
            ReplayGame();
     
        }

Obviously, this happens if invoke ReplayGame, more than once, then the problems begin

How can i make it more safe, or stop the thread...

replay=serializeMeh.giveBackDictionary();

if i put the statement above into the if statement below, will it stop the problem. does the isBusy bool prevents two threads entering the same place?

if (backgroundWorker1.IsBusy != true)            {                // Start the asynchronous operation.                backgroundWorker1.RunWorkerAsync();            }

What exactly are you trying to do? Before pasting some code here, would be nice to do some basic explanation of what is your project aobut. So we can have a clue about, and then its a way easier for us to help you out.
Now I dont know what are you doing, and how can I / we help you. So some basic explanation would be welcome.

I hope you understand.
Mitja

i think i mentioned it already.
replay is a dictionary that hold a number of move (starts from 1 and goes up as mor emoves are made in the chess game),- that is the key.
the value that it returns is an array of moves, 2 coordinates of the starting and end positions.

basically, the code works without the background worker. i tested it with a messagebox. I think two threads run , if i click the replay event (it is a menustrip control) twice, so i thought to put the replay reference with a code feeding it into the if statement.....

To keep it short, everything works.. i wanted to run the loop above in sleep. but i think replay dictionary changes in the middle, and makes a new array, that leads to random behavior of the algorithm (which is expressed when i reply the chess game).

And do you have any clue what might cause the dictionary change? Because from the code, which looks clean, I cant find any reason for that.

if (backgroundWorker1.IsBusy != true)
             {
                 // Start the asynchronous operation.
                 replay = serializeMeh.giveBackDictionary();
                 backgroundWorker1.RunWorkerAsync();
             }

i changed it to this. it works, but each time i replay, and add more moves, and replay again, the second time it runs the foreach loop is very slow.

is it normal for one thread to terminate a new to begin, could there be a lag between one background worker finishing and another beginning?

You only have one BackgroundWorker, so it can't be running two (or more) at the same time. I'd make sure none of the methods called in BackgroundWorker have side effects, i.e. they don't alter anything (files, data structures, etc.) and that nothing you are doing in the UI thread while the BackgroundWorker is running changes anything, either.

commented: Awesome help, thank you +0

Try surrounding your Foreach loop with a

Lock (dictionary) {

}

i locked it with my dictionary.. still there is a lag.
( public static Dictionary<int, int[]> replay;)

lock (replay)
            {
                foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
                {
                    makeSelfMoves = replay[item.Key];
                    codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);
                    PrintPieces(codeFile.PieceState());
                    System.Threading.Thread.Sleep(1000);
                }
            }

This is the only method that triggers GameReplay() method. it is a control that triggers and event.

    private void replayToolStripMenuItem_Click(object sender, EventArgs e)
    {
        DeSierializeNow();// deserializes the class with the dictionary being held. it isnt important what it exactly does, it simply return a dictionary, which i later need to use to feed into replay dictionary

        PrintPieces(codeFile.FirstTimeLoad());// That method resets the pieces array. making the chessboard look same as when the game starts.
        PrintPieces(codeFile.PieceState());// this method prints the pieces on the board
        ReplayGame();// this method replays all the moves. i.e. foreach loop runs through all the keys in teh replay dictionary.

    }

Code:

codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);

That method however, does make changes to the Dictionary , i later pass to replay Dictionary.

An extract from my chessCode:

        if (!Class2.replayIsOn)// this static bool gives access to the code if the GameReply is on or off. in a replay (when the code goes through the foreach loop), the access to the code should be barred. Therefore, the replay Dictionary has no source from which to change
        {
            // Serializing data
            if (WasntSerialized)
            {
                chess.DeSierializeNow();
                WasntSerialized = false;
            }


            if (!WasntSerialized)
            {
                b++;
               // positionArray.Add(b, ArrayOfRightPositions);
                Class2.rightPositions.Add(b, ArrayOfRightPositions);
                chess.activateMySavedPositions();// before serialization, it will go to the function and set the dictionary. That dictionary, will be then available through extraction by this method which is inside the ReplayGame method.    

Code:

replay = serializeMeh.giveBackDictionary();// 

But it doesnt change the replay.

                chess.SerializeNow();
                WasntSerialized = true;
            }
        }

Look at the control method again:

   private void replayToolStripMenuItem_Click(object sender, EventArgs e)
    {
        DeSierializeNow();
        notBeingUsed = true;
        PrintPieces(codeFile.FirstTimeLoad());
        PrintPieces(codeFile.PieceState());
        Class2.replayIsOn = true;// replay is on, so cant set a new dictionary
        ReplayGame();// here is where the foreach loop is executed. replay is on, means a new dictionary cant be set/changed.
        Class2.replayIsOn = false;// replay is off, so you can set a new dictionary.
        Game.WasntSerialized = false;
    }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.