Button with pause function

3

I have a small application that inserts images into the database. There are many images and sometimes I need to stop the execution for a period and continue at another time so as not to disturb the work of the client.

Anyway, my application is running very well, but I would like a function that pauses for , without losing what has already been done, and continue where it left off. It's possible?

The code is basically this:

private void bProcessar_Click(object sender, EventArgs e)
{
    DirectoryInfo di = new DirectoryInfo(pastaOriginal);
    FileInfo[] TotalArquivos = di.GetFiles();
    int quantidade = arquivos.Length;
    for (int i = 0; i < quantidade; i++)
    {
       sqlComando = .....;

    }    
 }
    
asked by anonymous 30.01.2015 / 12:28

4 answers

2

You can do this in several different ways! Control by database, Session or variables ...

Since you do not have the urgency to process everything immediately, I suggest you run your processing via Task with a Timer every X time, you can do as follows:

In a main method, you would have to create the Timer to run every X time, in this example, 1 minute is set:

System.Timers.Timer t = new System.Timers.Timer(TimeSpan.FromSeconds(60000).TotalSeconds);
t.AutoReset = true;
t.Elapsed += new ElapsedEventHandler(METODO_QUE_PROCESSA_ARQUIVOS);
t.Start();

You would replace the time of 60000 ms, for your desired time and would replace METODO_QUE_PROCESSA_ARQUIVOS with the name of your method that will do the processing (you already have).

In this way, it would function as if it were an asynchronous function, however, with a Timer to run every X time.

You can still set to process X files, every X time.

I hope you have helped! Thanks.

    
30.01.2015 / 12:53
2

There is a way. At this time the staff finds out something called separation of concepts ( in English ).

Many of the codes posted here that involve graphical interface makes processing within the interface itself. This is wrong. It may seem silly to separate but you have several reasons to do this. I will not go into details. But you've just discovered one of the reasons.

Just because it works does not mean it's right.

To solve this problem, processing must be separated from the interface. The interface should only trigger the processing, ie it should only call a method that processes the files. This method must belong to the other interface-independent class.

Well, it is possible to do a gambiarra within this for to solve otherwise, but it is a very bad thing to do and even more complicated to do right.

I usually do not like to just provide links but what you've done is a long way from what needs to be done and only when you walk more would you give more help. Other than that I would have to do everything for you.

This question in SO already gives a good indicator of how it could be made with modern techniques. The posted response indicates an MSDN article that really shows the right way to do it.

It may seem complicated, but doing it the right way is not simple.

I can think of other solutions, some without using asynchronicity, but none is simple. Processing data without blocking the UI is not something simple. It has even been simplified by using async but pausing and resuming does not have a ready way deal with. By default there is a way to cancel the asynchronous process through a token . To consider a token to pause you need to create your own mechanism. Luckily someone at Microsoft thought about it.

Another example using the same technique.

I do not like that solution using another technique but it's an alternative.

In this answer has an idea that does even more than you want.

What made me think that one of the problems you may have is that it is taking a long time to process because each file is being processed individually. Processing in parallel (asynchronicity already helps a lot in this) can increase processing performance in huge quantities. When you process files, the computer is waiting for the storage device to respond, and most of the time it does nothing. That is, the computer has the ability to process multiple simultaneous files.

    
30.01.2015 / 13:59
1

Do not pause the process, but stop it altogether

The ideal in a long process is that it can continue where it left off if it is interrupted.

Otherwise, if it is unintentionally interrupted, you either have to start and redo everything that has already been done or you will end up with inconsistencies such as having source data entered in the target twice.

Imagine you pause the process and when you return two hours later to continue the application is no longer there because the machine has been restarted.

Some ideas on how to make your process resilient to interruptions and to continue where you left off:

  • Rename the already-processed files (for example, from to

30.01.2015 / 15:22
1

It is possible. Here's the example, based on this MSDN article >.

You will need to create these classes:

public class PauseTokenSource
{
    private TaskCompletionSource<bool> m_paused;
    internal static readonly Task s_completedTask = Task.FromResult(true);

    public bool IsPaused
    {
        get { return m_paused != null; }
        set
        {
            if (value)
            {
                Interlocked.CompareExchange(
                    ref m_paused, new TaskCompletionSource<bool>(), null);
            }
            else
            {
                while (true)
                {
                    var tcs = m_paused;
                    if (tcs == null) return;
                    if (Interlocked.CompareExchange(ref m_paused, null, tcs) == tcs)
                    {
                        tcs.SetResult(true);
                        break;
                    }
                }
            }
        }
    }
    public PauseToken Token { get { return new PauseToken(this); } }

    internal Task WaitWhilePausedAsync()
    {
        var cur = m_paused;
        return cur != null ? cur.Task : s_completedTask;
    }
}

public struct PauseToken
{
    private readonly PauseTokenSource m_source;
    internal PauseToken(PauseTokenSource source) { m_source = source; }

    public bool IsPaused { get { return m_source != null && m_source.IsPaused; } }

    public Task WaitWhilePausedAsync()
    {
        return IsPaused ?
            m_source.WaitWhilePausedAsync() :
            PauseTokenSource.s_completedTask;
    }
}

Then in your code:

PauseTokenSource pts = null; // esse é o token de pausa

private async void bProcessar_Click(object sender, EventArgs e)
{
    pts = new PauseTokenSource();

    var token = pts.Token;

    Task.Run(async () => await ProcessaArquivos(token));

 }

 private async Task ProcessaArquivos(PauseToken token)
 {

    DirectoryInfo di = new DirectoryInfo(pastaOriginal);
    FileInfo[] TotalArquivos = di.GetFiles();
    int quantidade = arquivos.Length;
    for (int i = 0; i < quantidade; i++)
    {
       sqlComando = .....;

       await token.WaitWhilePausedAsync(); // aguarda caso estado IsPaused 
    }    

}

Finally a method for a pause / continue button:

private void buttonPause_Click(object sender, EventArgs e)
{
    if (pts != null)
    {
        pts.IsPaused = !pts.IsPaused;
    }
}
    
30.01.2015 / 14:09