I am trying to do what seems simple to me, but can't manage to implement it. I want to increment a simple variable in a Data flow Task...
The variable is set in the ReadWriteVariables, there is no output nor input columns.
This is the end-goal (I'll avoid sharing the monstrosity my current code is) :
public class ScriptMain : UserComponent
{
public override void PostExecute()
{
base.PostExecute();
Variables.intDatasourceUpdated++;
}
}
I suppose I'm missing something (very junior with C# and .Net), so any help would be appreciated.
Edit:
I want to increment my "updated" or my "inserted" variables depending on the lookup : lookup printscreen. Here, it is always "updated".
My error is : error printscreen. Note that it says "at Variables.get_intDatasourceInserted()" but I never go to that branch here. So I commented the increment line in the "insert script" and it worked.
But then, when I'll have the "insert" case, as I currently have it deactivated, it won't increment.
"The collection of variables locked for read and write access is not available outside of PostExecute".
You are posting your "Update" snippet, the error is saying you are trying to update intDatasourceInserted which likely in your "Insert"s PreExecute(). Which isn't allowed.
In either case you'll still have an issue, since each task there execute simultaneously, waiting for pipeline data, and variables don't work well between tasks inside one data flow, you'll probably need to mangle the data itself as it flows or access the altered variable outside the data flow in the control flow.
You need to decalre the variable outside of row processing.
public int counter = 0;
public void main()
{
counter++;
}
And at the end set the variable to counter.
post execute...
Variables.Counter = counter;
Usually this can be done, by defining a new C# variable. Set the value of the SSIS-variable to the new variable and then back again.
// Declare user-defined variable and increase the value by 1
int variableValue = Convert.ToInt32(Dts.Variables["myVariable"].Value);
variableValue++;
// Write the new value back into the variable
Dts.Variables["myVariable"].Value = variableValue;
Related
I am working on a little project in c# in forms (visual studio) and I am having a problem.
I have the following code in my forms.cs:
private void Dierbutton_Click(object sender, EventArgs e)
{
string name = AnimalNameTextbox.Text;
bool fleshEater = CarnivoorCheckbox.Checked;
Animal.Sizes size;
if (AnimalSizeBig.Checked)
{
size = Animal.Sizes.Big;
}
else if (AnimalCheckboxMedium.Checked)
{
size = Animal.Sizes.Medium;
}
else if (AnimalCheckboxSmall.Checked)
{
size = Animal.Sizes.Small;
}
else
{
MessageBox.Show("Vul een grootte in!");
}
Animal newAnimal = new Animal(size, fleshEater, name);
allAnimals.Add(newAnimal);
DierListbox.Items.Add(newAnimal.Name);
}
And the following code in my Animal.cs class:
namespace Circustrein_algoritmic
{
public class Animal
{
public enum Sizes
{
None = 0,
Small = 1,
Medium = 3,
Big = 5
}
public Sizes Size;
public bool Flesheater { get; set; }
public string Name { get; set; }
/// <param name="size">Size</param>
/// <param name="flesheater">True of flase wanneer dier vleeseter is</param>
/// <param name="name">Name</param>
public Animal(Sizes size, bool flesheater, string name)
{
Size = size;
Flesheater = flesheater;
Name = name;
}
public string getType()
{
return Flesheater ? "Flesheater" : "Planteater";
}
}
}
I am getting the error "use of unassigned local variable 'size'" in this piece of code in the forms.cs
Animal newAnimal = new Animal(size, fleshEater, name);
But when I change the code to this:
Animal newAnimal = new Animal(Animal.Sizes.Big, fleshEater, name);
The error changes to the following warning: "The variable 'size' is assigned but its value is never used.
So it is assigned, but it is not at the same time????
I do not want to change the code to this:
Animal newAnimal = new Animal(Animal.Sizes.Big, fleshEater, name);
Because I don't want my size to be pinned to Big, Medium, Small or None.
I have no clue what to do.
Does anyone have any tips?
Thanks in advance!
So it is assigned, but it is not at the same time????
I understand that these compiler messages are confusing, and apologize for that.
The error messages that deal with definite assignment and the warnings which identify possibly wrong code were added piecemeal, over time, and without a solid plan to keep them consistent.
When I was on the compiler team I made several attempts to get them more consistent and more clear, but that work had mixed success to say the least. A detailed exegesis of all those attempts would take us far afield; I've written some articles and answers about those in the past; one of them that might interest you is this three part series.
The simple explanation is that the error and the warning are using "assigned" to mean two different things. The error message is:
use of unassigned local variable 'size'
but that's not quite right. What it should say is something like "local variable size is not definitely assigned a value on all possible control flows before it is read".
If you look at your code you'll see that if the final else is taken, then size is never written, but on that code path it is still read, and that's an error. There's no value there to read!
You then remove the read, and the error goes away, because it is not an error to fail to initialize a variable that is never read. However, the code now looks wrong; you did work to attempt to initialize size and then you never made use of that work, so that's probably a mistake. The warning:
The variable 'size' is assigned but its value is never used.
Is using "assigned" to mean "at some point in this method you assigned a value to this local variable, but then you never read from it, so why did you assign that value?"
This warning is not seen that often; the compiler usually suppresses it. Why? Because this pattern is extremely common:
int dummy = Blah();
// Note, dummy is never read, but I want to observe it in the debugger.
But in your code the compiler knows that you are probably not using size for the purposes of debugging; you've only assigned it constants. There's no mystery here about what its value is; you can just read the code and know what its exact value will be on every control flow.
So that's the difference: in the error, "unassigned" means "not definitely assigned on every control flow" and in the warning, "assigned" means "assigned at least once".
I have no clue what to do.
There are two ways to proceed.
First technique: keep the assignments the same, but avoid the code path that lacks the assignment at the time of read. For example:
else
{
MessageBox.Show("Vul een grootte in!");
return;
}
Now there is no problem; the only path on which size is not assigned returns before size is read.
Second technique: Add an assignment on all paths:
else
{
MessageBox.Show("Vul een grootte in!");
size = Animal.Sizes.None;
}
Now there is an assignment on every path before the read.
If you hit the else statement, no value is ever assigned to size; hence the compilation error.
Either intialise the variable when declaring, or assign a value in the else block.
Okay, so the reason it's saying "use of unassigned variable" is that there is a path through the code that it could take (in your first code snippet), where it might not be assigned -- that happens if it hits your final if block (where you print the message).
You can fix it either by assigning size a value inside THAT part of the method too, or you could insert a "return" after the MessageBox.show, so that it would simple drop out of the method at that point without creating an "Animal" at all (and therefore not passing an uninitialized size along).
In addition to what the others have posted, I wanted to note that the error switching to "size is assigned but never used" is not quite a conflict/opposite of "use of unassigned" - if you're sitting there scratching your head and saying "make your mind up - is it assigned or not?!" then you can look to the other answers for details on the first error:
"use of unassigned" means "there are some possible paths in your code where this variable might not be assigned a value before it's used"; you can read a lot of tech info on this by googling for "c# definite assignemnt"
and the second error - "assigned but never used" basically means "size only ever appears on the left hand side of an =", so it's detecting that you assign a value to it, but then you don't ever actually make use of it
As you can imagine, the two aren't in conflict - it's possible to have a situation where you use a variable that might not have a value, and if you take that use away you're only left with code paths that assign a value but don't use it
I want to know the consequence of using a class level variable across different functions in a multi-threaded app.
I am creating a class variable and sharing it across get and set function.
The variable is bound to have a value like :
"testuser-2.3" {username-projectversion}
Code:
class Test()
{
private string key;
public Get(string something)
{
key = setToSOmething();
}
public Set(string something)
{
key = setToSOmething();
}
}
Is this code prone to fail in multithreaded environments? Like if two users are accessing diffrent versions of the project, will the "key" value will be diffrent at any random given point?
Thanks in advance.
I want to know the consequence of using a class level variable across different functions in a multi-threaded app.
What you're doing in your code will work, sort of, but it doesn't demonstrate the consequence of allowing multiple threads to modify a variable. It doesn't answer your question. It just means that you'll be okay with the particular thing you're doing with this particular variable.
In this case you're just assigning a different reference to your string variable. That's safe, in a way. You won't get any mangled strings, but it means that you don't know which string a given function will get when it reads the variable. In some scenarios that's not so bad, but it's a little chaotic.
The problem occurs when multiple threads interact with your variable in a way that isn't thread safe.
Here's a really simple test method I wrote without actually knowing what was going to happen:
public class MultithreadedStringTest
{
private string _sharedString;
[TestMethod]
public void DoesntMessUpStrings()
{
var inputStrings = "The quick fox jumped over the lazy brown dog".Split(' ');
var random= new Random();
Parallel.ForEach(Enumerable.Range(0, 1000), x =>
{
_sharedString += " " + inputStrings[random.Next(0, 9)];
});
var outputStrings = _sharedString.Trim().Split(' ');
var nonMangledStrings = outputStrings.Count(s => inputStrings.Contains(s));
Assert.AreEqual(1000, outputStrings.Length,
$"We lost {1000-outputStrings.Length} strings!");
Assert.AreEqual(nonMangledStrings, outputStrings.Length,
$"{outputStrings.Length-nonMangledStrings} strings got mangled.");
}
}
I'm starting with 10 words, and then, in a Parallel.Each loop appending 1000 words selected from those 10 to a single string from concurrent threads.
I expected the string to get mangled. It didn't. Instead what happened is that out of my 1000 words that I added, typically a few hundred just got lost.
We lost 495 strings!
Obviously that's not the particular operation that you're performing. But what it shows is that when we perform concurrent operations, we need to know that we're either calling a thread safe method or we're using some mechanism to prevent conflicts. We want to know how our code will behave and not cross our fingers and hope for the best.
If we're not careful with it the results will be unpredictable and inconsistent. It might work when you test it and fail later, and when it does it will be difficult to diagnose because you won't be able to see it happen.
Leaving aside the fact that Get and Set are both setting key in your code...
This code won't be prone to failure because of the nature of string. It's an immutable class, and the data is basically constructed elsewhere, and then your key assignment happens, as a single, atomic operation. (It's a reference or basically a pointer assignment).
So...even if you were to have two setters, key will always reference a valid string. Depending on the use of this code, though, the order in which the assignments actually happen could be counterintuitive. Say your get actually returns the string...set(get() + "X") could eventually lose Xes if called multiple times from multiple threads. Because all the get calls could get the same old string and perform the string addition on that. But this is you assuming set AND get together are an atomic operation. The accepted answer here:
reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?
explains this better than I'm doing.
The contrary example would be if you were to use StringBuilder and actually modify the data inside the class...that would not be thread-safe and would certainly require a lock.
Updating answer to explain my reasoning behind my argument that the OP's code is fundamentally thread-safe considered on its own. Consider the following code which attempts to add thread-safety:
public partial class MainWindow : Window
{
private object emergencyLock = new object();
private string _status;
public string status
{
get
{
//make sure if an emergency is happening we get the best possible string.
lock (emergencyLock)
{
return _status;
}
}
set
{
//we could also lock here instead of in GetEmergencyString()..which would fix the get+set=atomic issue
_status = value;
}
}
private string GetEmergencyString()
{
//this function understands an emergency is happening
lock (emergencyLock)
{
//Maybe I'm fetching this string from a database, or building it by hand
//It takes a while...We'll simulate this here
Thread.Sleep(1000);
return "Oh crap, emergency!";
}
}
private void Normal_Button_Click(object sender, RoutedEventArgs e)
{
status = "Nothing much going on.";
}
private void Emergency_Button_Click(object sender, RoutedEventArgs e)
{
//GetEmergencyString() is evaluated first..finally returns a string,
//and THEN the assignment occurs as a single operation
status = GetEmergencyString();
}
}
I'll make the following points about this code:
It does prevent a status seeker from getting a "boring" status during an emergency. It also potentially forces the status seeker to wait a full second before getting that status...Effectively solving nothing, most likely.
Also consider that even single-threaded, there's a fundamental issue here. The fundamental issue is NOT thread safety (in my opinion). The fundamental issue is delay. Better solutions? Fixing the delay. Active notification of the new state..Events, pubsub, etc. A state machine. Even a volatile bool IsEmergency is much better than the "thread-safety" I've added. Any active, intelligent logic in the code. Maybe you don't want the emergency state to be overwritten by the normal state? Again...not a threading issue.
In to following tutorial : http://www.albahari.com/threading/
They say that the following code :
for (int i = 0; i < 10; i++)
new Thread (() => Console.Write (i)).Start();
is non deterministic and can produce the following answer :
0223557799
I thought that when one uses lambda expressions the compiler creates some kind of anonymous class that captures the variables that are in use by creating members like them in the capturing class.
But i is value type, so i thought that he should be copied by value.
where is my mistake ?
It will be very helpful if the answer will explain how does closure work, how do it hold a "pointer" to a specific int , what code does generated in this specific case ?
The key point here is that closures close over variables, not over values. As such, the value of a given variable at the time you close over it is irrelevant. What matters is the value of that variable at the time the anonymous method is invoked.
How this happens is easy enough to see when you see what the compiler transforms the closure into. It'll create something morally similar to this:
public class ClosureClass1
{
public int i;
public void AnonyousMethod1()
{
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
ClosureClass1 closure1 = new ClosureClass1();
for (closure1.i = 0; closure1.i < 10; closure1.i++)
new Thread(closure1.AnonyousMethod1).Start();
}
So here we can see a bit more clearly what's going on. There is one copy of the variable, and that variable has now been promoted to a field of a new class, instead of being a local variable. Anywhere that would have modified the local variable now modifies the field of this instance. We can now see why your code prints what it does. After starting the new thread, but before it can actually execute, the for loop in the main thread is going back and incrementing the variable in the closure. The variable that hasn't yet been read by the closure.
To produce the desired result what you need to do is make sure that, instead of having every iteration of the loop closing over a single variable, they need to each have a variable that they close over:
for (int i = 0; i < 10; i++)
{
int copy = i;
new Thread(() => Console.WriteLine(copy));
}
Now the copy variable is never changed after it is closed over, and our program will print out 0-9 (although in an arbitrary order, because threads can be scheduled however the OS wants).
As Albahari states, Although the passing arguments are value types, each thread captures the memory location thus resulting in unexpected results.
This is happening because before the Thread had any time to start, the loop already changed whatever value that inside i.
To avoid that, you should use a temp variable as Albahari stated, or only use it when you know the variable is not going to change.
i in Console.Write(i) is evaluated right when that statement is about to be executed. That statement will be executed once thread has been fully created and started running and got to that code. By that time loop has moved forward a few times and thus i can be any value by then. Closures, unlike regular functions, have visibility into local variables of a function in which it is defined (what makes them useful, and way to shoot oneself in a foot).
I have worked with c# code for past 4 years, but recently I went through a scenario which I never pass through. I got a damn project to troubleshoot the "Index out of range error". The code looks crazy and all the unnecessary things were there but it's been in production for past 3 years I just need to fix this issue. Coming to the problem.
class FilterCondition
{
.....
public string DataSetName {get; set;}
public bool IsFilterMatch()
{
//somecode here
Dataset dsDataSet = FilterDataSources.GetDataSource(DataSetName); // Static class and Static collection
var filter = "columnname filtername"
//some code here
ds.defaultview.filter= filter;
var isvalid = ds.defaultView.rowcount > 0? true : false;
return isValid;
}
}
// from a out side function they put this in a parallel loop
Parallel.ForEach()
{
// at some point its calling
item.IsFiltermatch();
}
When I debug, dsDataSet I saw that dsDataSet is modified my multiple threads. That's why race condition happens and it failed to apply the filter and fails with index out of Range.
My question here is, my method is Non-static and thread safe, then how this race condition happening since dsDataset is a local variable inside my member function. Strange, I suspect something to do with Parallel.Foreach.
And when I put a normal lock over there issue got resolved, for that also I have no answer. Why should I put lock on a non-static member function?
Can anyone give me an answer for this. I am new to the group. if I am missing anything in the question please let me know. I can't copy the whole code since client restrictions there. Thanks for reading.
Because it's not thread safe.
You're accessing a static collection from multiple threads.
You have a misconception about local variables. Although the variable is local, it's pointing at an object which is not.
What you should do is add a lock around the places where you read and write to the static collection.
Problem: the problem lies within this call
FilterDataSources.GetDataSource(DataSetName);
Inside this method you are writing to a resource that is shared.
Solution:
You need to know which field is being written here and need to implement locking on it.
Note: If you could post your code for the above method we would be in a better position to help you.
I believe this is because of specific (not-stateless, not thread safe, etc) implementation of FilterDataSources.GetDataSource(DataSetName), even by a method call it seems this is a static method. This method can do different things even return cached DataSet instance, intercept calls to a data set items, return a DataSet wrapper so you are working with a wrapper not a data set, so a lot of stuff can be there. If you want to fine let's say "exact line of code" which causes this please show us implementation of GetDataSource() method and all underlying static context of FilterDataSource class (static fields, constructor, other static methods which are being called by GetDataSource() if such exists...)
Suppose we have the following code:
void AFunction()
{
foreach(AClass i in AClassCollection)
{
listOfLambdaFunctions.AddLast( () => { PrintLine(i.name); } );
}
}
void Main()
{
AFunction();
foreach( var i in listOfLambdaFunctions)
i();
}
One might think that the above code would out the same as the following:
void Main()
{
foreach(AClass i in AClassCollection)
PrintLine(i.name);
}
However, it doesn't. Instead, it prints the name of the last item in AClassCollection every time.
It appears as if the same item was being used in each lambda function. I suspect there might be some delay from when the lambda was created to when the lambda took a snapshot of the external variables used in it.
Essentially, the lambda is holding a reference to the local variable i, instead of taking a "snapshot" of i's value when the lambda was created.
To test this theory, I tried this code:
string astr = "a string";
AFunc fnc = () => { System.Diagnostics.Debug.WriteLine(astr); };
astr = "changed";
fnc();
and, surprise, it outputs changed!
I am using XNA 3.1, and whichever version of C# that comes with it.
My questions are:
What is going on?
Does the lambda function somehow store a 'reference' to the variable or something?
Is there any way around this problem?
This is a modified closure
See: similar questions like Access to Modified Closure
To work around the issue you have to store a copy of the variable inside the scope of the for loop:
foreach(AClass i in AClassCollection)
{
AClass anotherI= i;
listOfLambdaFunctions.AddLast( () => { PrintLine(anotherI.name); } );
}
does the lambda function somehow store a 'reference' to the variable or something?
Close. The lambda function captures the variable itself. There is no need to store a reference to a variable, and in fact, in .NET it is impossible to permanently store a reference to a variable. You just capture the entire variable. You never capture the value of the variable.
Remember, a variable is a storage location. The name "i" refers to a particular storage location, and in your case, it always refers to the same storage location.
Is there anyway around this problem?
Yes. Create a new variable every time through the loop. The closure then captures a different variable every time.
This is one of the most frequently reported problems with C#. We're considering changing the semantics of the loop variable declaration so that a new variable is created every time through the loop.
For more details on this issue see my articles on the subject:
http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/
what is going on? does the lambda function somehow store a 'reference' to the variable or something?
Yes exactly that; c# captured variables are to the variable, not the value of the variable. You can usually get around this by introducing a temp variable and binding to that:
string astr = "a string";
var tmp = astr;
AFunc fnc = () => { System.Diagnostics.Debug.WriteLine(tmp); };
especially in foreach where this is notorious.
Yes, the lambda stores a reference to the variable (conceptually speaking, anyway).
A very simple workaround is this:
foreach(AClass i in AClassCollection)
{
AClass j = i;
listOfLambdaFunctions.AddLast( () => { PrintLine(j.name); } );
}
In every iteration of the foreach loop, a new j gets created, which the lambda captures.
i on the other hand, is the same variable throughout, but gets updated with every iteration (so all the lambdas end up seeing the last value)
And I agree that this is a bit surprising. :)
I've been caught by this one as well, as said by Calgary Coder, it is a modified closure. I really had trouble spotting them until I got resharper. Since it is one of the warnings that resharper watches for, I am much better at identifying them as I code.