I copied this example from here
I have seen many similar examples. Most of them say they're using the Async CTP. I'm using Visual Studio 11 on Windows 8 though so that does not apply. As shown, the error says TaskEx doesn't exist. I assume I'm missing a reference but don't know which one.
This page is http://users.zoominternet.net/~charleswatson/pic.png.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static Random rnd = new Random();
static void Main(string[] args)
{
//Do some other heavy duty background task in this thread
StartHotel();
Console.WriteLine("StartHotel called..");
Console.ReadLine();
}
static void StartHotel()
{
Console.WriteLine("Starting Hotel..");
for (int i = 0; i < 10; i++)
{
string name = "Chef" + i;
CookDish(name, "Dish" + i);
Console.WriteLine("Asked {0} to start cooking at {1}", name, DateTime.Now.ToString());
}
}
static async void CookDish(string chefName, string dish)
{
//Induce a random delay
int delay = rnd.Next(1000, 4000);
//Cook is cooking - Task
await TaskEx.Delay(delay);
//Write the result - StuffAfterAwait
Console.WriteLine("Chef {0} Finished at {1}", chefName, DateTime.Now.ToString());
}
}
}
In the CTP we were unable to add new features to the Task type so we did the pragmatic thing and just made a new TaskEx type. In the final release there will be no such type; those methods will just be on Task like you'd expect.
Replace TaskEx with Task. At the top of the .cs file, you'll need:
using System.Threading.Tasks;
Much of the sample code I've seen refers to TaskEx, and the estimable Mr. Lippert seems to be indicating that's an artifact of their development process. If you're using the Developer Preview, calls like Run, WhenAll, and Delay are already methods of the class Task rather than of TaskEx. The release tools should be the same.
Related
Background
My colleague thinks reads in multithreaded C# are reliable and will always give you the current, fresh value of a field, but I've always used locks because I was sure I'd experienced problems otherwise.
I spent some time googling and reading articles, but I mustn't be able to provide google with correct search input, because I didn't find exactly what I was after.
So I wrote the below program without locks in an attempt to prove why that's bad.
Question
I'm assuming the below is a valid test, then the results show that the reads aren't reliable/fresh.
Can someone explain what this is caused by? (reordering, staleness or something else)?
And link me to official Microsoft documentation/section explaining why this happens and what is the recommended solution?
If the below isn't a valid test, what would be?
Program
If there are two threads, one calls SetA and the other calls SetB, if the reads are unreliable without locks, then intermittently Foo's field "c" will be false.
using System;
using System.Threading.Tasks;
namespace SetASetBTestAB
{
class Program
{
class Foo
{
public bool a;
public bool b;
public bool c;
public void SetA()
{
a = true;
TestAB();
}
public void SetB()
{
b = true;
TestAB();
}
public void TestAB()
{
if (a && b)
{
c = true;
}
}
}
static void Main(string[] args)
{
int timesCWasFalse = 0;
for (int i = 0; i < 100000; i++)
{
var f = new Foo();
var t1 = Task.Run(() => f.SetA());
var t2 = Task.Run(() => f.SetB());
Task.WaitAll(t1, t2);
if (!f.c)
{
timesCWasFalse++;
}
}
Console.WriteLine($"timesCWasFalse: {timesCWasFalse}");
Console.WriteLine("Finished. Press Enter to exit");
Console.ReadLine();
}
}
}
Output
Release mode. Intel Core i7 6700HQ:
Run 1: timesCWasFalse: 8
Run 2: timesCWasFalse: 10
Of course it is not fresh. The average CPU nowadays has 3 layers of Caches between each cores Registers and the RAM. And it can take quite some time for a write to one cache to be propagate to all of them.
And then there is the JiT Compiler. Part of it's job is dead code dection. And one of the first things it will do is cut out "useless" variables. For example this code tried to force a OOM excpetion by running into the 2 GiB Limit on x32 Systems:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OOM_32_forced
{
class Program
{
static void Main(string[] args)
{
//each short is 2 byte big, Int32.MaxValue is 2^31.
//So this will require a bit above 2^32 byte, or 2 GiB
short[] Array = new short[Int32.MaxValue];
/*need to actually access that array
Otherwise JIT compiler and optimisations will just skip
the array definition and creation */
foreach (short value in Array)
Console.WriteLine(value);
}
}
}
The thing is that if you cut out the output stuff, there is a decent chance that the JiT will remove the variable Array inlcuding the instantionation order. The JiT has a decent chance to reduce this programming to doing nothing at all at runtime.
volatile is first preventing the JiT from doing any optimisations on that value. And it might even have some effect on how the CPU processes stuff.
I eventually pared this down to an incredibly simple test (from a huge 500,000 line system). When I run this test app
using Jint;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var jint = new JintEngine();
jint.DisableSecurity();
jint.MaxStatements = 1000;
jint.SetFunction("foo",new Action( Foo));
jint.Run("foo();");
Foo();
}
public static void Foo()
{
Debug.WriteLine("foo");
var sw = new Stopwatch();
sw.Start();
for (int j = 0; j < 500000; j++)
{
var k = new Byte[50];
}
sw.Stop();
Debug.WriteLine(sw.ElapsedTicks);
}
}
}
I get this
foo
55150
foo
13279
Note that the only difference is that the first Foo invocation is called by jint, the second one is called directly. There is no jint / js/ etc involved in the loop in Foo. When called via jint it takes 2 to 3 times as long to run the code!
It feels like jint inserted something into the environment that slows things down when its in the stack but I cant see what. It has some CAS calls, I took those out, didnt make a difference. I am stumped.
It really feels like it that CAS stuff, but I can't get it to behave consistently.
I tried a simple test but it didn't like out variables
As a simple test, I wrote this (perhaps there is something simple wrong with it, but I also had trouble with patterns and with tuples)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
public class Program
{
static void Main(string[] args)
{
Runner runner = new ConsoleApplication2.Runner();
Point p = new ConsoleApplication2.Point();
runner.PrintCoordinates(p);
}
}
public class Point
{
int x = 20;
int y = 50;
public void GetCoordinates(out int a, out int b)
{
a = x;
b = y;
}
}
public class Runner
{
public void PrintCoordinates(Point p)
{
p.GetCoordinates(out int x, out int y);
Console.WriteLine($"({x}, {y})"); // x does not exist in current context
}
}
}
According to this post, where the PrintCoordinates example method comes from:
Note: In Preview 4, the scope rules are more restrictive: Out variables are scoped to the statement they are declared in. Thus, the above example will not work until a later release.
The new tuples suffer from a similar problem, though it seems you can partially work around that with a NuGet download:
Note: Tuples rely on a set of underlying types, that aren’t included in Preview 4. To make the feature work, you can easily get them via NuGet:
Right-click the project in the Solution Explorer and select “Manage NuGet Packages…”
Select the “Browse” tab, check “Include prerelease” and select “nuget.org” as the “Package source”
Search for “System.ValueTuple” and install it.
I'm trying to write a game in C# that runs on my cmd on Windows and I need to be able to write to any part of the box to do that. I found WriteAt used extensively for this purpose, however it doesn't seem to work in VS 2010. I get the error: "The name WriteAt does not exist in the current context"
I have the default:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
at the top of my code. So why can't I use WriteAt?
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GamePCL
{
class Program
{
static void Main(string[] args)
{
Console.Clear();
for (int x = 0; x < 24; x += 2)
{
WriteAt("█", x, 0);
WriteAt("█", x, 30);
}
}
}
}
When you call a method without an object or type prefix, as in this case WriteAt() (as opposed to for example Console.WriteLine(), which is called on the Console type), the method must exist in the current context, i.e. in the current class.
You copied that code from MSDN without copying the relevant method:
protected static void WriteAt(string s, int x, int y)
{
try
{
Console.SetCursorPosition(origCol+x, origRow+y);
Console.Write(s);
}
catch (ArgumentOutOfRangeException e)
{
Console.Clear();
Console.WriteLine(e.Message);
}
}
Here's the library I'm using:
http://taskscheduler.codeplex.com/wikipage?title=Install&referringTitle=Documentation
Here's the code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32.TaskScheduler;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
var p = new Program();
p.EnumAllTasks();
}
void EnumAllTasks() {
using (TaskService ts = new TaskService())
EnumFolderTasks(ts,ts.RootFolder);
}
void EnumFolderTasks(TaskService ts, TaskFolder fld) {
var tasks = fld.Tasks.Where(t => t.Name.Equals("test-task", StringComparison.OrdinalIgnoreCase));
foreach (Task task in tasks)
ActOnTask(ts, task);
}
void ActOnTask(TaskService ts, Task t) {
//ea.Path
Console.WriteLine(t.Name);
Console.WriteLine(t.Path);
Console.WriteLine(((ExecAction)t.Definition.Actions.First()).Path);
var ea = (ExecAction)t.Definition.Actions.First();
ea.Path = ea.Path + ".coolio/test.exe";
UpdateFirstAction(t, new ExecAction(ea.Path+".coolio/test.exe",ea.Arguments,ea.WorkingDirectory));
//ts.s
// Do something interesting here
}
void UpdateFirstAction(Task t, Microsoft.Win32.TaskScheduler.Action action) {
if (t.TaskService.HighestSupportedVersion >= new Version(1, 2)) {
Console.WriteLine("HERE");
t.Definition.Actions.RemoveAt(0);
}
t.Definition.Actions.Add(action);
}
}
}
I added the 'UpdateFirstAction' method based upon the following: https://taskscheduler.codeplex.com/discussions/203704
I want to be able to update the path that's getting executed, and the above link seems to imply that updating the collection is enough.
How do I actually save the changes? All of the documentation I've read seems to describe how to read things only.
You can omit the UpdateFirstAction method. The library since version 1.6.1 has fixed the bug from that discussion item. The code is correct on how to edit the Path property. To update the task with the changed Path, you only need to call t.RegisterChanges() at the point you are calling UpdateFirstAction.