|
Yeah, barely had an introduction to Assembly (VAX Macro 11), quite a bit of C, just a dabbling of C++, and now C# for the past twenty years.
|
|
|
|
|
I can strongly recommend C# in Depth[^]. You can buy copies from Amazon.
|
|
|
|
|
Thanks for the suggestion
|
|
|
|
|
Calin Negru wrote: to get better at c++ I need to improve my c# skills Why do you think this ?blockquote class="quote">Calin Negru wrote: I remember seeing helper constructs that make certain operations when dealing with lists easier but at that time I could not understand themCan you understand them now ? Study LINQ !
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Bill your post seems to have some formatting problems
|
|
|
|
|
I need to call Google's People API from a WPF app. Google has mandated that you cannot use embedded browsers any more[^].
Therefore, my app need to open the browser, presumably with Process.Start() to Google's Authentication page, and then somehow detect if/when the user has been authenticated.
How would you go about that?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
|
Microsoft provides a group of thread-safe collections, but conspicuously does not provide a thread-safe List<T>. What is the reason? Is it not feasible to make a thread-safe version of a List<T>?
I need an ordered, sortable collection that is thread-safe.
I might get flamed, but I'm about to copy and paste some code I found on the internet. On stack exchange, I found the following post:
https://codereview.stackexchange.com/questions/62033/creating-a-thread-safe-list-using-a-lock-object[^]
To me, it looks like it would work and be thread-safe.
I'm wondering if some more experienced and respected members can tell me if this code looks like it might indeed be thread safe. The key bit about this code is that it uses callbacks to be able to keep the collection locked even while enumerating it or performing some other types of access.
I have reproduced the code below for convenience:
(If you consider this post inappropriate due to its length, please let me know, and I won't do it again.)
public class ConcurrentList<T> : IList<T>
{
#region Fields
private IList<T> _internalList;
private readonly object lockObject = new object();
#endregion
#region ctor
public ConcurrentList()
{
_internalList = new List<T>();
}
public ConcurrentList(int capacity)
{
_internalList = new List<T>(capacity);
}
public ConcurrentList(IEnumerable<T> list)
{
_internalList = list.ToList();
}
#endregion
public T this[int index]
{
get
{
return LockInternalListAndGet(l => l[index]);
}
set
{
LockInternalListAndCommand(l => l[index] = value);
}
}
public int Count
{
get
{
return LockInternalListAndQuery(l => l.Count());
}
}
public bool IsReadOnly => false;
public void Add(T item)
{
LockInternalListAndCommand(l => l.Add(item));
}
public void Clear()
{
LockInternalListAndCommand(l => l.Clear());
}
public bool Contains(T item)
{
return LockInternalListAndQuery(l => l.Contains(item));
}
public void CopyTo(T[] array, int arrayIndex)
{
LockInternalListAndCommand(l => l.CopyTo(array, arrayIndex));
}
public IEnumerator<T> GetEnumerator()
{
return LockInternalListAndQuery(l => l.GetEnumerator());
}
public int IndexOf(T item)
{
return LockInternalListAndQuery(l => l.IndexOf(item));
}
public void Insert(int index, T item)
{
LockInternalListAndCommand(l => l.Insert(index, item));
}
public bool Remove(T item)
{
return LockInternalListAndQuery(l => l.Remove(item));
}
public void RemoveAt(int index)
{
LockInternalListAndCommand(l => l.RemoveAt(index));
}
IEnumerator IEnumerable.GetEnumerator()
{
return LockInternalListAndQuery(l => l.GetEnumerator());
}
#region Utilities
protected virtual void LockInternalListAndCommand(Action<IList<T>> action)
{
lock (lockObject)
{
action(_internalList);
}
}
protected virtual T LockInternalListAndGet(Func<IList<T>, T> func)
{
lock (lockObject)
{
return func(_internalList);
}
}
protected virtual TObject LockInternalListAndQuery<TObject>(Func<IList<T>, TObject> query)
{
lock (lockObject)
{
return query(_internalList);
}
}
#endregion
}
The difficult we do right away...
...the impossible takes slightly longer.
modified 21-May-23 16:33pm.
|
|
|
|
|
Deja vu.
.Values collection of a concurrent dictionary.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Gerry, thank you for your post. I didn't mention in the original post that I need an ordered collection that is sortable.
I don't see that the .Values collection supports sorting.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
"Sortable". Before, during, or after? One time or repeatedly? You can built multiple dictionaries over the same set all having a different order ... the "keys collection" is then in order (with which to retrieve the "values"). Or, sort the values before loading them with an "entity id.".
All the concurrent collections require some sort of "destaging" if you want a "list"
I didn't think you actually meant you wanted to be able to (live) sort a "concurrent" (list) file.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
modified 22-May-23 18:07pm.
|
|
|
|
|
? [^] ... a Collection with unspecified order.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
You woke up just for that?
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Well, there's this internal class from the .NET Framework source:
ThreadSafeList - Reference Source[^]
But the obvious question is, what's the expected use-case? The Concurrent collections are typically designed to be as lock-free as possible. Appending an item to a list from multiple threads doesn't lend itself to that approach. And if two threads append an item at the same time, what order do you expect them to appear in?
Perhaps you're looking for something more like a producer-consumer pattern[^]? Or perhaps a ConcurrentQueue[^]?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: And if two threads append an item at the same time, what order do you expect them to appear in? That's why the collection should support sorting.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
As Gerry said, sorting at what point?
If the list must always be sorted, then there's no option but to lock the entire list on every modification.
If you only want the list sorted after you've finished populating it, then it's better to use an unsorted concurrent collection (eg: ConcurrentBag<T> ), and then sort the items when you consume them.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Just noting that usually when I design something where threads are a problem, and once I consider it, I very seldom want a collection itself that is thread safe.
I end up writing a container that controls access to the collection.
I can't be sure about all that I consider but I do know that there are optimizations for access which can only be controlled via container. Adding those if one is using the collection directly can be a problem.
Sometimes I even make the container into a collection. Where the real collection is a attribute (not parent). Yes that is more work but it still insures control.
|
|
|
|
|
You could use ImmutableList as an alternative to locking.
1) Copy the reference to the list into a temporary variable used (not a field)
2) Call add/delete/whatever on your reference copy from step 1. Notice this will NOT update the original list but return a reference to a new list. Keep this result separate, do not override the reference you got in step 1.
3) Use Interlocked.CompareExchange to assign this new reference back to the place you got it from in step 1
If Interlocked.CompareExchange does not return the value you got in 1), then it means someone else altered the list at the same time you where doing it. You can take the returned value and run step 2) and 3) again (yes, all of this can be written as a somewhat readable loop).
This will avoid locks, but at the risk of running the list modification multiple times in case of conflict. If performance is important you would need to measure if this is faster than a simple lock. If both are fast enough, use whatever you find most readable.
If you are updating the list concurrently order is of course not guarantied - but it is guarantied multiple operations performed in step 2) above would be performed as an atomic operation - you will never access the list where it only contains some of the pending modifications.
|
|
|
|
|
I think that is a brilliant idea! I will consider it.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Is it possible to open a browser with Process.Start("www.someplace.com") and wait for a callback?
If so, what would that look like? I need to call Google People API in the default browser and wait for the redirect URL.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Callback? What callback?
No. You're "fire and forget" launching a new process that runs independently from your code. There is no callback or notification of anything completing in the browser.
You can call the Google API using an HttpClient and you'll have much greater control over the request and response process.
|
|
|
|
|
Ya, I was just hoping.
Thanks anyhow
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
This?
Window: DOMContentLoaded event - Web APIs | MDN
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
That fires inside the browser. It's not raised, or even exposed, to a separate process that launched the browser.
|
|
|
|
|