Be sure Weakreference is still existing after IsAlive - c#

If i iterate over a list of Weakreferences, how can i be sure, the reference still exists, after proofing via _ref.IsAlive?
For example i have this piece of code, where scopeReferences is a of Weakreferences:
foreach (var _ref in scopeReferences)
{
if (_ref.IsAlive)
{
if (_ref.Target is ScriptScope)
{
// Is it alive any more?
((ScriptScope)_ref.Target).SetVariable(name, value);
}
}
}
Maybe some one knows the answer, i just don't want to create any problems due to the fact, i don't know what's going on in this part. Thank you all a lot!

You could copy it to a variable, after which you either have it or you don't, and you can safely test it:
foreach (var _ref in scopeReferences)
{
ScriptScope tmp = _ref.Target as ScriptScope;
if (tmp != null)
{
tmp.SetVariable(name, value);
}
}

Related

Refactor C# code from inner foreach loop to outer foreach loop

My code currently looks like like:
foreach(var request in requestsList){
foreach(var myVar in request.anotherList){
if(myVar.hasPermissions()) {
//do something
}
}
}
requestsList is a List of Requests.
myVar.hasPermissions() requires a connection to the database so I want to minimize the number of calls to database. I want to move it outside of the inner foreach loop and make only one call per request.
I am trying to achieve something like this:
foreach(var request in requestsList){
//check for permissions
boolean perm = myVar.hasPermissions(); //database call to check permissions
foreach(var myVar in request.anotherList){
if(perm) {
//do something
}
}
}
All I want to do is to move the hasPermissions() outside of inner foreach loop.
The problem I am facing is that I don't have access to myVar in the outer foreach loop. Both the loops iterating over lists is making it difficult for me.
If hasPermission is relatively static, i.e. you are certain that it wouldn't change across the runs of the outer loop, you could cache permissions as you check them:
IDictionary<MyVarType,bool> checked = new IDictionary<MyVarType,bool>();
foreach(var request in requestsList){
foreach(var myVar in request.anotherList) {
bool permitted;
if (!checked.TryGetValue(myVar, out permitted)) {
permitted = myVar.hasPermissions();
checked.Add(myVar, permitted);
}
if(permitted) {
//do something
}
}
}
This way you would make exactly one call to hasPermissions per distinct instance of myVar; all subsequent checks would come from the checked cache.
Without much more detail about your classes, we can only speculate how best to solve the problem. Assuming your anotherList consists of something like a list of users, you could cache the result of the check so you don't check again for the same user.
You can add a public field that uses Lazy to cache the result of calling hasPermissions - you have to initialize it in the constructors:
public class User {
public bool hasPermissions() { // check database for permissions
var ans = false; // ...
return ans;
}
public Lazy<bool> cachedPermissions;
public User() {
UncachePermissions();
}
public void UncachePermissions() => cachedPermissions = new Lazy<bool>(() => hasPermissions());
}
Now you can access the cachedPermissions instead of calling hasPermissions:
foreach (var request in requestsList) {
foreach (var myVar in request.anotherList) {
if (myVar.cachedPermissions.Value) {
//do something
}
}
}
and hasPermissions will only be called once per User object. If it is possible that multiple User objects exist for a single database call, then more details on your classes and methods would be needed.
I added the UncachePermissions method to reset the cache as otherwise you could use really old values of hasPermissions which could cause issues. If that might be a common problem, you could cache outside the objects as part of the looping:
var permissionCache = new Dictionary<User, bool>();
foreach (var request in requestsList) {
foreach (var myVar in request.anotherList) {
bool permission;
if (!permissionCache.TryGetValue(myVar, out permission)) {
permission = myVar.hasPermissions();
permissionCache.Add(myVar, permission);
}
if (permission) {
//do something
}
}
}
I think you are calling it the minimum number of times, in the top loop.
If you think about it another way...
//First get all the 'another' guys:
var allAnother = requestsList.SelectMany(anotherList => anotherList).ToList();
//If you don't have to check them all
var permitGuys = allAnother.Distinct().Where(a => a.hasPermissions()).ToList();
//Do something with them
foreach(var permitGuy in permitGuys)
{
//Do something
}

Threads and access to a shared list

I'm encountering (I hope) a deadlocking issue with a WCF service I'm trying to write.
I have the following lock on a function that "locates" a particular item im the list:
CIPRecipe FindRecipe_ByUniqueID(string uniqueID)
{
lock (_locks[LOCK_RECIPES])
{
foreach (var r in _recipes.Keys)
{
if (_recipes[r].UniqueID == uniqueID)
{
return _recipes[r];
}
}
}
return null;
}
However, various functions reiterate through this list and always apply the same LOCK for example ....
lock (_locks[LOCK_RECIPES_NO_ADD_OR_REMOVE])
{
foreach (var r in _recipes)
{
r.Value.UpdateSummary();
summaries.Add((RecipeSummary)r.Value.Summary);
}
}
What I suspect is, an item in _recipes in the above example has suddenly called a function which ultimately calls the first function - "CIPRecipe FindRecipe_ByUniqueID(string uniqueID)" and this is causing a deadlock when it is reached in the iteration.
I need to stop this list changing whilst I'm iterating through it. Can someone advise me the best practice?
Thanks
What you want is to use a ReaderWriterLockSlim, this will let unlimited concurrent readers through but only a single writer through and block all readers while the writer is writing.
This assumes _locks has been chagned from a object[] to a ReaderWriterSlim[]
//On Read
CIPRecipe FindRecipe_ByUniqueID(string uniqueID)
{
var lockObj = _locks[LOCK_RECIPES];
lockObj.EnterReadLock();
try
{
foreach (var r in _recipes.Keys)
{
if (_recipes[r].UniqueID == uniqueID)
{
return _recipes[r];
}
}
}
finally
{
lockObj.ExitReadLock();
}
return null;
}
//On write
var lockObject = _locks[LOCK_RECIPES]; //Note this now uses the same lock object as the other method.
lockObj.EnterWriteLock();
try
{
foreach (var r in _recipes)
{
r.Value.UpdateSummary();
summaries.Add((RecipeSummary)r.Value.Summary);
}
}
finally
{
lockObj.ExitWriteLock();
}
I don't know if it will solve your deadlock issue, if it is caused by you allowing reads during a write it may.
Perhaps a ConcurrentDictionary is called for here?

Is this linq update correct?

I gotta run a maybe one-time or potentially once every few months update on this table. Basically to allow other programs that reference to run faster. I really thought this update looked right but it did not change the data. Is what I am doing wrong?
public static void UpdateMFGtoID()
{
DataDataContext _db = new DataDataContext();
foreach (VINPatternDecode vin in _db.VINPatternDecodes)
{
vin.DivisionName = GetMfgID(vin.DivisionName.Replace("~",""));
_db.SubmitChanges();
}
}
It should work, but its better to Dispose your resources, and maybe, depending on the amount of data (if its small) just use one SubmitChanges():
using (DataDataContext _db = new DataDataContext())
{
foreach (VINPatternDecode vin in _db.VINPatternDecodes)
{
vin.DivisionName = GetMfgID(vin.DivisionName.Replace("~",""));
}
_db.SubmitChanges();
}
The using calls the Dispose function implicit.

SmartThreadPool - Is it possible to pass delegate method with method parameters?

I have a long running process called ImportProductInformation called by a consoleapp that I'm trying to speed up, which appears to be an excellent candidate for thread-pooling, so I did a little searching and came across SmartThreadPool on CodeProject and am trying to implement it.
ImportProductInformation currently requires an "item", which is just a single entity-framework row pulled from a list. SmartThreadPool uses a delegate called "WorkItemCallback", but if I build it like below it complains about "Method name expected" in the foreach loop on smartThreadPool.QueueWorkItem, as it appears I can't pass my params to the delegated method. What am I missing here? I'm sure it's something stupid...noob lacking experience with delegates...any help would be appreciated:
public static void ImportProductInformation_Exec()
{
// List
List<productinformation> _list = GetProductInformation();
// Import
if (_list != null)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
foreach (var item in _list)
{
smartThreadPool.QueueWorkItem
(new WorkItemCallback
(ImportProductInformation(item)));
}
smartThreadPool.WaitForIdle();
smartThreadPool.Shutdown();
}
}
public void ImportProductInformation(productinformation item)
{
// Do work associated with "item" here
}
If I change the loop to this I get "Method is used like a Type" in the build error:
foreach (var item in _list)
{
ImportProductInformation ipi =
new ImportProductInformation(item);
smartThreadPool.QueueWorkItem(new WorkItemCallback(ipi));
}
Ended up getting it to work with this:
public class ProductInformationTaskInfo
{
public productinformation ProductInformation;
public ProductInformationTaskInfo(productinformation pi)
{
ProductInformation = pi;
}
}
public class PI
{
foreach (var item in _list)
{
ProductInformationTaskInfo pi =
new ProductInformationTaskInfo(item);
smartThreadPool.QueueWorkItem
(new WorkItemCallback
(ImportProductInformation), pi);
}
public static object ImportProductInformation(Object _pi)
{
ProductInformationTaskInfo pi = (ProductInformationTaskInfo)_pi;
var item = pi.ProductInformation;
// Do work here
}
}
I don't know or have the SmartThreadPool, the following is approximate:
foreach (var item in _list)
{
var itemCopy = item;
smartThreadPool.QueueWorkItem
(dummy => ImportProductInformation(itemCopy));
}
You may have to do some fixing.
This works because the lambda captures a variable from the containing method. And that's why you need itemCopy.
But note that the normal ThreadPool is not suited for longrunning tasks, the same may hold for the SmartThreadPool. It should also keep a limit on the number of threads, and when ImportProductInformation does mainly I/O threading might not help at all.
You can use anonymous methods:
int a = 15;
String b = "hello world!";
ThreadPool.QueueUserWorkItem((state)=>SomeFunction(a,b));

How to remove a single, specific object from a ConcurrentBag<>?

With the new ConcurrentBag<T> in .NET 4, how do you remove a certain, specific object from it when only TryTake() and TryPeek() are available?
I'm thinking of using TryTake() and then just adding the resulting object back into the list if I don't want to remove it, but I feel like I might be missing something. Is this the correct way?
The short answer: you can't do it in an easy way.
The ConcurrentBag keeps a thread local queue for each thread and it only looks at other threads' queues once its own queue becomes empty. If you remove an item and put it back then the next item you remove may be the same item again. There is no guarantee that repeatedly removing items and putting them back will allow you to iterate over the all the items.
Two alternatives for you:
Remove all items and remember them, until you find the one you want to remove, then put the others back afterwards. Note that if two threads try to do this simultaneously you will have problems.
Use a more suitable data structure such as ConcurrentDictionary.
You can't. Its a bag, it isn't ordered. When you put it back, you'll just get stuck in an endless loop.
You want a Set. You can emulate one with ConcurrentDictionary. Or a HashSet that you protect yourself with a lock.
The ConcurrentBag is great to handle a List where you can add items and enumerate from many thread, then eventually throw it away as its name is suggesting :)
As Mark Byers told, you can re-build a new ConcurrentBag that does not contains the item you wish to remove, but you have to protect this against multiple threads hits using a lock. This is a one-liner:
myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));
This works, and match the spirit in which the ConcurrentBag has been designed for.
As you mention, TryTake() is the only option. This is also the example on MSDN. Reflector shows no other hidden internal methods of interest either.
Mark is correct in that the ConcurrentDictionary is will work in the way you are wanting. If you wish to still use a ConcurrentBag the following, not efficient mind you, will get you there.
var stringToMatch = "test";
var temp = new List<string>();
var x = new ConcurrentBag<string>();
for (int i = 0; i < 10; i++)
{
x.Add(string.Format("adding{0}", i));
}
string y;
while (!x.IsEmpty)
{
x.TryTake(out y);
if(string.Equals(y, stringToMatch, StringComparison.CurrentCultureIgnoreCase))
{
break;
}
temp.Add(y);
}
foreach (var item in temp)
{
x.Add(item);
}
public static void Remove<T>(this ConcurrentBag<T> bag, T item)
{
while (bag.Count > 0)
{
T result;
bag.TryTake(out result);
if (result.Equals(item))
{
break;
}
bag.Add(result);
}
}
This is my extension class which I am using in my projects. It can a remove single item from ConcurrentBag and can also remove list of items from bag
public static class ConcurrentBag
{
static Object locker = new object();
public static void Clear<T>(this ConcurrentBag<T> bag)
{
bag = new ConcurrentBag<T>();
}
public static void Remove<T>(this ConcurrentBag<T> bag, List<T> itemlist)
{
try
{
lock (locker)
{
List<T> removelist = bag.ToList();
Parallel.ForEach(itemlist, currentitem => {
removelist.Remove(currentitem);
});
bag = new ConcurrentBag<T>();
Parallel.ForEach(removelist, currentitem =>
{
bag.Add(currentitem);
});
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public static void Remove<T>(this ConcurrentBag<T> bag, T removeitem)
{
try
{
lock (locker)
{
List<T> removelist = bag.ToList();
removelist.Remove(removeitem);
bag = new ConcurrentBag<T>();
Parallel.ForEach(removelist, currentitem =>
{
bag.Add(currentitem);
});
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
public static ConcurrentBag<String> RemoveItemFromConcurrentBag(ConcurrentBag<String> Array, String Item)
{
var Temp=new ConcurrentBag<String>();
Parallel.ForEach(Array, Line =>
{
if (Line != Item) Temp.Add(Line);
});
return Temp;
}
how about:
bag.Where(x => x == item).Take(1);
It works, I'm not sure how efficiently...

Categories