Get clipboard text in async method - c#

I have a problem getting clipboard text via the async method. Because it always returns an empty value (while it's not empty). This is a simple demonstration of the problem:
private async void button_Click(object sender, EventArgs e)
{
string result = await Task<string>.Run(() =>
{
System.Threading.Thread.Sleep(3000);
return Clipboard.GetText(); //returns empty! (but clipboard is not empty)
});
MessageBox.Show(result);
}
I'm sure that the clipboard is not empty. what's the solution?

It doesn't work because the clipboard only works when the COM threading model (apartment) is STA while your Task apartment is MTA.
You can't change the apartment of the Task, BUT you can use Thread instead. Thread has a SetApartmentState method.
STA and MTA explained here
But I've found a solution to create an STA Task !
The trick is to run an STA thread using a Task:
public static Task<T> StartSTATask<T>(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
var thread = new Thread(() =>
{
try
{
var result = func();
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
So now you can make it work like this:
private async void button1_Click(object sender, EventArgs e)
{
var result = await StartSTATask(() =>
{
Thread.Sleep(3000);
return Clipboard.GetText();
});
MessageBox.Show(result);
}

This should work:
private static int counter;
private async void button1_Click(object sender, EventArgs e)
{
counter++;
button1.Text = counter.ToString();
// Solution 1 (preferred)
await LongOperation();
Debug.WriteLine("Solution 1 completed for counter " + counter);
// Solution 2 (use if LongOperation is CPU-bound)
var t = Task.Run(LongOperation);
await t;
Debug.WriteLine("Solution 2 completed for counter " + counter);
Debug.WriteLine(Clipboard.GetText());
}
private async Task LongOperation()
{
await Task.Delay(10000);
}
Click 3 times in a row on button1. Result:
// Click 3 times in a row on the button. Result:
// After 10 seconds:
Solution 1 completed for counter 3
Solution 1 completed for counter 3
Solution 1 completed for counter 3
// After 10 more seconds:
Solution 2 completed for counter 3
<clipboard content>
Solution 2 completed for counter 3
<clipboard content>
Solution 2 completed for counter 3
<clipboard content>

Related

How do i stop pause a task in c# .net

I have tried but it is not working i want to stop and pause this task:: code below
private void checkingTimer()
{
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(startPollingAwaitingURLs);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
dispatcherTimer.Start();
}
private static object _lock_CrawlingSync = new object();
private static bool blBeingProcessed = false;
private static List<Task> lstCrawlingTasks = new List<Task>();
private static List<string> lstCurrentlyCrawlingUrls = new List<string>();
private void btnTest_Click(object sender, RoutedEventArgs e)
{
using (WebCrawlerEntities1 db = new WebCrawlerEntities1())
{
db.tblMainUrls.RemoveRange(db.tblMainUrls);
db.SaveChanges();
}
}
private void clearDBandStart(object sender, RoutedEventArgs e)
{
dtStartDate = DateTime.Now;
crawlPage(urlTextbox.Text.normalizeUrl(), 0, urlTextbox.Text.normalizeUrl(), DateTime.Now);
checkingTimer();
}
private void startPollingAwaitingURLs(object sender, EventArgs e)
{
lock (UserLogs)
{
string srPerMinCrawlingspeed = (irCrawledUrlCount.ToDouble() / (DateTime.Now - dtStartDate).TotalMinutes).ToString("N2");
string srPerMinDiscoveredLinkSpeed = (irDiscoveredUrlCount.ToDouble() / (DateTime.Now - dtStartDate).TotalMinutes).ToString("N2");
string srPassedTime = (DateTime.Now - dtStartDate).TotalMinutes.ToString("N2");
UserLogs.Insert(0, $"{DateTime.Now} polling awaiting urls \t processing: {blBeingProcessed} \t number of crawling tasks: {lstCrawlingTasks.Count}");
UserLogs.Insert(0, $"Total Time: {srPassedTime} Minutes \t Total Crawled Links Count: {irCrawledUrlCount.ToString("N0")} \t Crawling Speed Per Minute: {srPerMinCrawlingspeed} \t Total Discovered Links : {irDiscoveredUrlCount.ToString("N0")} \t Discovered Url Speed: {srPerMinDiscoveredLinkSpeed} ");
}
logMesssage($"polling awaiting urls \t processing: {blBeingProcessed} \t number of crawling tasks: {lstCrawlingTasks.Count}");
if (blBeingProcessed)
return;
lock (_lock_CrawlingSync)
{
blBeingProcessed = true;
lstCrawlingTasks = lstCrawlingTasks.Where(pr => pr.Status != TaskStatus.RanToCompletion && pr.Status != TaskStatus.Faulted).ToList();
int irTasksCountToStart = _irNumberOfTotalConcurrentCrawling - lstCrawlingTasks.Count;
if (irTasksCountToStart > 0)
using (WebCrawlerEntities1 db = new WebCrawlerEntities1())
{
var vrReturnedList = db.tblMainUrls.Where(x => x.isCrawled == false && x.CrawlTryCounter < _irMaximumTryCount)
.OrderBy(pr => pr.DiscoverDate)
.Select(x => new
{
x.Url,
x.LinkDepthLevel
}).Take(irTasksCountToStart * 2).ToList();
logMesssage(string.Join(" , ", vrReturnedList.Select(pr => pr.Url)));
foreach (var vrPerReturned in vrReturnedList)
{
var vrUrlToCrawl = vrPerReturned.Url;
int irDepth = vrPerReturned.LinkDepthLevel;
lock (lstCurrentlyCrawlingUrls)
{
if (lstCurrentlyCrawlingUrls.Contains(vrUrlToCrawl))
{
logMesssage($"bypass url since already crawling: \t {vrUrlToCrawl}");
continue;
}
lstCurrentlyCrawlingUrls.Add(vrUrlToCrawl);
}
logMesssage($"starting crawling url: \t {vrUrlToCrawl}");
lock (UserLogs)
{
UserLogs.Insert(0, $"{DateTime.Now} starting crawling url: \t {vrUrlToCrawl}");
}
var vrStartedTask = Task.Factory.StartNew(() => { crawlPage(vrUrlToCrawl, irDepth, null, DateTime.MinValue); }).ContinueWith((pr) =>
{
lock (lstCurrentlyCrawlingUrls)
{
lstCurrentlyCrawlingUrls.Remove(vrUrlToCrawl);
logMesssage($"removing url from list since task completed: \t {vrUrlToCrawl}");
}
});
lstCrawlingTasks.Add(vrStartedTask);
if (lstCrawlingTasks.Count > _irNumberOfTotalConcurrentCrawling)
break;
}
}
blBeingProcessed = false;
}
}
so is there a way to stop my task up ahead and pause should i mre.set() or .Set()
my application is a web crawler that get links from any website.
so when pressing on a button web crawling task pause or stop and restart ... any methods to do or changes
Try :
Thread.Sleep() to pause your task.
Thread.Interrupt() to stop your sleeping task.
Technically you can't stop a Task. Task isn't running anything but only waiting for a completion of something it was bound for. You can stop the code, running in the Thread. For example, with ManualResetEventSlim.
private readonly ManualResetEventSlim _mre = new ManualResetEventSlim(true); // not paused initially
public void Pause()
{
_mre.Reset();
}
public void Resume()
{
_mre.Set();
}
In the method where you want to pause the execution when requested, just add.
_mre.Wait();
Few tips
Use Task.Run instead of Task.Factory.StartNew and learn the difference.
Find something about Producer/Consumer programming pattern and related thread-safe collections.
Say hello to Asynchronous programming.

Parallel.Invoke Not working as expected in C#

I am calling a SSIS Package from my C# code. The package processes one by one file and deletes it from a particular folder.
As the package processes one file by one, I want show the progress in a progressbar.
I have written this function to fetch the progress:
private void fileIteration(string folderPath)
{
int initialFileCount, fileCount, processCount;
initialFileCount = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly).Length;
this.Invoke(new MethodInvoker(delegate (){ progressBar1.Value = initialFileCount;}));
if (initialFileCount > 0)
{
fileCount = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly).Length;
while (fileCount != 0)
{
// Thread.Sleep(2000);
fileCount = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly).Length;
processCount = initialFileCount - fileCount;
this.Invoke(new MethodInvoker(delegate () { progressBar1.Increment(processCount); }));
initialFileCount = initialFileCount + processCount;
}
}
}
Since both tasks should execute in parallel, I am invoking like this
Parallel.Invoke(
() => fileIteration(folderPath),// for prgressbar
() => results = package.Execute()); // for calling package
However both are not working together for me. I tried to keep 100 files and kept folder open so as to crosscheck the fast process is making me to unable to see the progressbar. It is not the case. Any suggestions?
The Parallel.Invoke is a blocking method. If you are calling it from the UI thread, a deadlock will occur, because the fileIteration method calls back the UI thread in order to update the progress bar. So everything will get stuck.
This method does not return until each of the provided operations has completed, regardless of whether completion occurs due to normal or exceptional termination.
My suggestion is to ditch both the Parallel.Invoke and the Invoke(new MethodInvoker shenanigans, and embrace the async/await:
private async void Button1_Click(object sender, EventArgs e)
{
int filesCountInit = await GetFilesCountAsync();
if (filesCountInit == 0) return;
progressBar1.Value = 0;
var ssisTask = Task.Run(() => _package.Execute());
while (!ssisTask.IsCompleted)
{
await Task.WhenAny(ssisTask, Task.Delay(1000));
int filesCount = await GetFilesCountAsync();
int percentDone = Math.Max(0, 100 - (filesCount * 100 / filesCountInit));
progressBar1.Value = percentDone;
}
if (ssisTask.Status == TaskStatus.RanToCompletion)
progressBar1.Value = 100;
var results = await ssisTask;
// Display the results
}
private Task<int> GetFilesCountAsync()
{
return Task.Run(() => Directory.GetFiles(
_folderPath, "*.*", SearchOption.TopDirectoryOnly).Length);
}
Parallel.Invoke does NOT ensure parallel execution.
[...]Executes each of the provided actions, POSSIBLY in parallel.[...]
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.invoke?view=netcore-3.1
Try spawning an explicit thread to ensure parallel execution of the progress monitor code piece.

Processing on shared variable by parallel tasks

I am beginning with task library. I wrote simple code like
private void button1_Click(object sender, EventArgs e)
{
simpleMost();
}
string mesg;
void simpleMost()
{
mesg = "";
button1.Enabled = false;
Task t1 = new Task(delegate { makeResult(1); });
Task t2 = new Task(delegate { makeResult(2); });
Task t3 = new Task(delegate { makeResult(3); });
t1.Start();
t2.Start();
t3.Start();
t1.Wait();
t2.Wait();
t3.Wait();
richTextBox1.Text = mesg;
button1.Enabled = true;
}
void makeResult(int a)
{
mesg += "\nTask" + a;
}
I click my button1 again and again and get following outputs
1.
Task3
Task1
Task2
2.
Task1
Task2
Task3
3.
Task1
Task2
Task3
4.
Task2
Task3
5.
Task1
Task3
6.
Task1
Task2
In 4,5,6 cases why does not makeResult work correctly. When I checked the Task states after wait statements they are found all completed but one of them misses the correct execution of function passed to it
You have several tasks, each of which is modifying the same shared resource in a non-atomic way.
mesg += "\nTask" + a;
is effectively:
mesg = mesg + "\nTask" + a;
... so if one task reads mesg, then another task writes a new value to it, then the first task will concatenate the strings using the old value, and write that back to the variable.
The simplest way to avoid this would be to use locking, so that only one thread can execute the modification statement at a time. It's not as elegant as it might be, but it should remove the race condition you currently have.
I think sometimes 2 tasks trying to access to "mesg" at the same time. Try it with a lock.
object syncObject = new object();
void makeResult(int a)
{
lock (syncObject)
{
mesg += "\nTask" + a;
}
}

Is it possible to execute two async methods in parallel?

If I execute two tasks, I can execute the two tasks at the same time and wait until the two tasks are finished. With this code:
Task<bool> tsk01 = Task.Run(()=> my code; return true);
Task<bool> tsk02 = Task.Run(()=> my code; return true);
Task.WaitAll(tsk01, tsk02);
//next code
In this case the following code is only executed when all tasks are finished. But the application is not blocked.
However if I have this code:
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
Task<bool> tsk01 = miMetodoAsync01();
Task<bool> tsk02 = miMetodoAsync02();
Task.WaitAll(tsk01, tsk02);
}
private async Task<bool> miMetodoAsync02()
{
return await TaskEx.Run<bool>(() =>
{
Int64 resultado = 0;
for (Int64 i = 1; i < 1000000000; i++)
{
resultado = resultado + 1;
}
return true;
}).ConfigureAwait(false);
}
private async Task<bool> miMetodoAsync01()
{
return await TaskEx.Run<bool>(() =>
{
Int64 resultado = 0;
for (Int64 i = 1; i < 1000000000; i++)
{
resultado = resultado + 1;
}
return true;
}).ConfigureAwait(false);
}
In this second option the application is blocked because the WaitAll seems to wait for a response from the tasks that never happens.
Why in the first case the application is not blocked and in the second one it is?
Both your examples will block the UI thread. That's what Task.WaitAll means.
However, you can use TaskEx.WhenAll:
await TaskEx.WhenAll(tsk01, tsk02);
The method Task.WaitAll will block the UI thread as it waits for all tasks to return before continuing.
The code examples that you gave for creating a Task are basically the same (albeit written slightly different ways). Both the return Task<bool>.
The difference is the function being run inside both of your lambda expressions. Your first example has a "my code" reference and returns. The second example you created two counters.
If your "my code" is defined differently than the the counters created in the second example, or if you are only returning true in your lambda expression, then you will get the appearance of one waiting over the other.
Simply returning true will end the threads immediately after they are created. Where-as the counter takes time to compute (also depending on your CPU speed).
If you add the same counter into your function of the first example, you will find that both take the same time, and Task.WaitAllblocks your UI. You can use the System.Diagnositics.StopWatch class to time it.
static void Main(string[] args)
{
string test = Console.ReadLine();
System.Diagnostics.Stopwatch t = new System.Diagnostics.Stopwatch();
t.Start();
Task<bool> task1 = Task.Run<bool>(() => { return true; });
Task<bool> task2 = Task.Run<bool>(() => { return true; });
Task.WaitAll(task1, task2);
t.Stop();
Console.WriteLine("Elapsed time: " + t.Elapsed);
System.Diagnostics.Stopwatch t2 = new System.Diagnostics.Stopwatch();
t2.Start();
Task<bool> task3 = asyncMethod1();
Task<bool> task4 = asyncMethod2();
Task.WaitAll(task3, task4);
t2.Stop();
Console.WriteLine("Elapsed time: " + t2.Elapsed);
Console.Read();
}

Problems with scheduling tasks from a UI .continuewith task

My application schedules a long running task using the following code:
Task.Factory.StartNew<bool>((a) => WorkTask1(),
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => WorkCompletedTask1(antecedent.Result),
TaskScheduler.FromCurrentSynchronizationContext());
WorkCompletedTask1 is scheduled and displays results on the UI as expected. Depending on results from WorkTask1, WorkCompletedTask1 may schedule additional tasks using the following statement:
Task.Factory.StartNew<bool>((a) => WorkTask2(),
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => WorkCompletedTask2(antecedent.Result),
TaskScheduler.FromCurrentSynchronizationContext());
WorkTask2 does NOT run on a separate thread as expected; it runs on the UI thread which is blocked until WorkTask2 completes. I thought the TaskCreationOptions.LongRunning would guarantee a separate thread.
Any suggestions on why this does not work? I can schedule addition tasks from UI and non-UI tasks, just not from a .continuewith task in the UI.
Broken Sample Project Code
In an empty Windows Forms project with button1 button on the form, this code does NOT work as expected (Windows 7 VS2010 Express Net 4.0). T2 and T3 run in the UI thread, not a worker thread.
Add a listBox1 to your button1 form and try the following:
private delegate void DelegateSendMsg(String msg);
private DelegateSendMsg m_DelegateSendMsg;
private TaskScheduler uiSched;
private Process thisProcess;
private string
thisProcessName,
thisProcessId,
uiThreadName,
nonuiStatus = "Non-UI",
uiStatus = "UI";
private void Form1_Load(object sender, EventArgs e)
{
thisProcess = Process.GetCurrentProcess();
thisProcessName = thisProcess.ProcessName;
thisProcessId = thisProcess.Id.ToString();
uiThreadName = CurrentThread;
m_DelegateSendMsg = this.SendMsg;
uiSched = TaskScheduler.FromCurrentSynchronizationContext();
SendMsg("UI thread name is " + CurrentThread);
}
//create the name of the current task
public string CurrentThread
{
get
{
string threadId = null;
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
threadId = thisProcess.Id.ToString() + "=" + thisProcessName;
else
threadId = thisProcessId
+ "=" + thisProcessName
+ "/" + Thread.CurrentThread.Name;
threadId += ":" + Thread.CurrentThread.ManagedThreadId + " ";
return threadId;
}
}
//validate if the function is running in the expected UI state or not
public bool MeetsUIExpectations(string functionName, string expectedStatus)
{
bool rc = true;
string currentThreadName = CurrentThread;
string text =
"Function " + functionName + " running in thread " + currentThreadName;
if ((currentThreadName == uiThreadName) & expectedStatus == uiStatus)
text += ": UI status as expected";
else if ((currentThreadName != uiThreadName) & expectedStatus == nonuiStatus)
text += ": non-UI status as expected";
else
{
text += ": UI status is NOT as expected!"
+ " Expected: " + expectedStatus
+ "; running in thread" + currentThreadName;
rc = false;
}
SendMsg(text);
return rc;
}
//display a single text message
private void SendMsg(String msg)
{
if (this.InvokeRequired)
try { this.Invoke(m_DelegateSendMsg, "UI context switch: " + msg); }
catch (Exception) { }
else
{
listBox1.Items.Add(msg);
listBox1.TopIndex = listBox1.Items.Count - 1;
}
}
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<bool>((a) =>
T1(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T1Completed(antecedent.Result), uiSched);
}
private bool T1()
{
//get the name of the currently running function and validate UI status
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T1Completed(bool successful)
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
if (successful)
{
Task.Factory.StartNew<bool>((a) =>
T2(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T2Completed(antecedent.Result), uiSched);
}
}
private bool T2()
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T2Completed(bool successful)
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
Task.Factory.StartNew<bool>((a) =>
T3(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T3Completed(antecedent.Result), uiSched);
}
private bool T3()
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T3Completed(bool successful)
{
//get the name of the currently running function and validate UI status
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
SendMsg("All functions completed");
}
In .NET 4.0 you have to pass TaskScheduler.Default explicitly. You picked the wrong overload to to this (see below).
Some General Stuff
In a continuation on the UI thread the TaskScheduler is still UI thread returned by FromCurrentSynchronizationContext method. Therefore, all new Tasks you start are scheduled on the UI thread too unless you pass a TaskScheduler explicitly:
Here is a code sample:
Task.Factory.StartNew(foo => {}, TaskScheduler.Default)
Feel free to use whatever TaskScheduler you need, but you need to state it explicitly.
Get the Right Overload
There are quite a few overloads for StartNew<T>. In your code below you pick the wrong one, which causes TaskScheduler.Default to act as state (a value passed as a to T3) rather than the actual scheduler:
var options = TaskCreationOptions.LongRunning
| TaskCreationOptions.AttachedToParent;
// overload with Func<bool>, CancellationToken, options and TaskScheduler
Task.Factory.StartNew<bool>(() => T2(), new CancellationToken(),
options, TaskScheduler.Default);
// overload with Func<object, bool> with state and options
// scheduler acts as state here instead of actual scheduler, and
// is therefore just passed as (a) to T3 (state is an object, thus
// can also be a TaskScheduler instance)
Task.Factory.StartNew<bool>((a) => T3(),
TaskScheduler.Default, // state, not scheduler
options);
Obviously this way you won't get the scheduling you want, but the default behaviour described above.
Additional Information for .NET 4.5
In .NET 4.5, there is TaskContinuationOptions.HideScheduler to change this behavior. See New TaskCreationOptions and TaskContinuationOptions in .NET 4.5 by Stephen Toub for more details on the new options and let me quote a code sample out of it:
// code sample copied from blog post stated above
Task.Factory.StartNew(() =>
{
// #2 long-running work, so offloaded to non-UI thread
}).ContinueWith(t =>
{
// #3 back on the UI thread
Task.Factory.StartNew(() =>
{
// #4 compute-intensive work we want offloaded to non-UI thread (bug!)
});
}, CancellationToken.None,
TaskContinuationOptions.HideScheduler, // <-- new option stated in text
TaskScheduler.FromCurrentSynchronizationContext());
Working Sample Project Code
In an empty Windows Forms project with button1 button on the form, this code works as expected (Windows 7, .NET 4.0):
private void button1_Click(object sender, EventArgs e)
{
var uiSched = TaskScheduler.FromCurrentSynchronizationContext();
button1.Enabled = false;
// this HardWork-task is not blocking, as we have
// TaskScheduler.Default as the default scheduler
Task.Factory.StartNew(HardWork)
.ContinueWith(t =>
{
button1.Enabled = true;
// this HardWork-task will block, as we are on the
// UI thread scheduler
Task.Factory.StartNew(HardWork)
.ContinueWith(t2 =>
{
button1.Enabled = false;
// this one will not, as we pass TaskScheduler.Default
// explicitly
Task.Factory.StartNew(HardWork,
new CancellationToken(),
TaskCreationOptions.None,
TaskScheduler.Default).ContinueWith(t3 =>
{
button1.Enabled = true;
}, uiSched); // come back to UI thread to alter button1
}, uiSched); // come back to UI thread to alter button1
}, uiSched); // come back on UI thread to alter button1
}
public void HardWork()
{
int i = 0;
while(i < Int32.MaxValue) i++;
}

Categories