I'm trying to start one thread, receive string from it and then start n-counts of threads with the received string. Code:
private void button2_Click(object sender, EventArgs e)
{
string post = null;
sync = new ManualResetEvent(false);
var thr = new Thread[1];
thr[0] = new Thread(delegate() { post = create_note(); });
thr[0].IsBackground = true;
thr[0].Start();
sync.WaitOne();
decimal value = Program.Data.numericUpDown1;
int i = 0;
int j = (int)(value);
thr = new Thread[j];
for (; i < j; i++)
{
thr[i] = new Thread(() => invite(post));
thr[i].IsBackground = true;
thr[i].Start();
}
}
public string create_note()
{
while (true)
{
string acc = "";
string proxy = "";
if (Program.Data.checkBox1 || Program.Data.checkBox2)
{
if (Program.Data.checkBox1)
Proxy.type = "http";
else if (Program.Data.checkBox2)
Proxy.type = "socks5";
lock (locker)
{
if (Proxy.proxies.Count == 0)
{
foreach (string prox in File.ReadAllLines(proxy_path))
{
if (prox.Contains(":"))
Proxy.proxies.Add(prox);
}
}
}
proxy = rand_proxy();
}
else if (!Program.Data.checkBox1 && !Program.Data.checkBox2)
Proxy.type = "none";
if (edit_accs.Count == 0)
{
break;
}
else
acc = edit_accs.Dequeue();
Od_post od_post = new Od_post(acc, proxy, Proxy.type);
string login = od_post.Auth();
if ()
{
string url = rand_url();
var text = new RandomString(Program.Data.textBox3).ToString();
string wall_post_text = od_post.wall_post_text(get_text(text), url);
if (wall_post_text == "Good")
{
string image_add = od_post.image_add(post_image_path);
if (image_add.Split('|')[0] == "Good")
{
if (Program.Data.checkBox5)
{
string change_name = od_post.change_name();
if (change_name == "Changed")
{
}
else
{
}
}
sync.Set();
return image_add.Split('|')[1];
}
else
{
}
}
else
{
}
}
else
{
lock (locker)
{
accs.Enqueue(acc);
Proxy.proxies.Remove(proxy);
}
}
}
return "Failed";
}
But it doesn't work. My app hangs, and the post doesn't receive the return value from create_note(). Why?
thr[0].Start();
sync.WaitOne();
This is a pretty common mistake when using a thread. Threading can give you two benefits. One is that code can run concurrently, allowing you to get more work done if you have a machine with multiple cores. And more commonly, it can run code asynchronously, a consideration when you have a user interface that you want to keep responsive.
You are getting neither. It does not run concurrently, your main thread isn't doing any work since it is waiting for the thread to complete. And it doesn't run asynchronously either, your main thread is frozen while the thread is doing its job.
You instead get all the disadvantages of a thread. A classic threading bug is a "race", your code has one. You hope that the "post" variable is assigned after the WaitOne() method completes. It might be, but the odds are just not that good. Since you call Set() before the assignment executes. It can only work correctly when you call Set() after the assignment. Deadlock is another classic threading bug, I don't see one but your debugger can easily show you. Deadlock is very likely here because you are freezing your main thread. Making calls like Invoke() on the thread is going to deadlock.
There's a very simple substitute for your code that does everything that you hope your current code does, minus the threading bugs:
string post = create_note();
Problem solved.
Minus addressing the reason that you considered writing this code in the first place. Which does require that you move all of the code that's now after the WaitOne() call into a callback that runs when the thread completes. Such code tends to be difficult to write, dealing with asynchronicity isn't that easy. But you can get help from .NET to get this right, like the BackgroundWorker.RunWorkerCompleted event, the Task class with its TaskScheduler.FromCurrentSynchronizationContext() method. And the async keyword added to C# version 5.
Related
I have a critical section (using locked scope).
I'd like that only the latest incoming thread "sleeps" on it. Hence - once the critical section is locked, every incoming thread "terminates" all previous sleeping ones.
Is there a way to achieve this using C#?
Thank you
The mechanism that seemed most effective for accomplishing this was to use Tasks, so the solution below is actually asynchronous, rather than synchronous, as the code came out much simpler that way. If you need it to be synchronous, you can just synchronously wait on the Tasks.
public class SingleWaiterLock
{
private bool realLockTaken = false;
private TaskCompletionSource<bool> waiterTCS = null;
private object lockObject = new object();
public Task<bool> WaitAsync()
{
lock (lockObject)
{
if (!realLockTaken)
{
realLockTaken = true;
return Task.FromResult(true);
}
if (waiterTCS == null)
{
waiterTCS = new TaskCompletionSource<bool>();
return waiterTCS.Task;
}
else
{
waiterTCS.SetResult(false);
waiterTCS = new TaskCompletionSource<bool>();
return waiterTCS.Task;
}
}
}
public void Release()
{
lock (lockObject)
{
if (waiterTCS != null)
{
waiterTCS.SetResult(true);
waiterTCS = null;
}
else
{
realLockTaken = false;
}
}
}
}
The boolean returned from the wait method indicates whether you actually acquired the lock (if it returns true) or were booted by someone coming later (returning false). The lock should only be released (but must always be released) when wait returns true.
By using the below code firstly some of the calls are not getting made lets say out of 250 , 238 calls are made and rest doesn't.Secondly I am not sure if the calls are made at the rate of 20 calls per 10 seconds.
public List<ShowData> GetAllShowAndTheirCast()
{
ShowResponse allShows = GetAllShows();
ShowCasts showCast = new ShowCasts();
showCast.showCastList = new List<ShowData>();
using (Semaphore pool = new Semaphore(20, 20))
{
for (int i = 0; i < allShows.Shows.Length; i++)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((taskId) =>
{
showCast.showCastList.Add(MapResponse(allShows.Shows[i]));
}));
pool.Release();
t.Start(i);
}
}
//for (int i = 0; i < allShows.Shows.Length; i++)
//{
// showCast.showCastList.Add(MapResponse(allShows.Shows[i]));
//}
return showCast.showCastList;
}
public ShowData MapResponse(Show s)
{
CastResponse castres = new CastResponse();
castres.CastlistResponse = (GetShowCast(s.id)).CastlistResponse;
ShowData sd = new ShowData();
sd.id = s.id;
sd.name = s.name;
if (castres.CastlistResponse != null && castres.CastlistResponse.Any())
{
sd.cast = new List<CastData>();
foreach (var item in castres.CastlistResponse)
{
CastData cd = new CastData();
cd.birthday = item.person.birthday;
cd.id = item.person.id;
cd.name = item.person.name;
sd.cast.Add(cd);
}
}
return sd;
}
public ShowResponse GetAllShows()
{
ShowResponse response = new ShowResponse();
string showUrl = ClientAPIUtils.apiUrl + "shows";
response.Shows = JsonConvert.DeserializeObject<Show[]>(ClientAPIUtils.GetDataFromUrl(showUrl));
return response;
}
public CastResponse GetShowCast(int showid)
{
CastResponse res = new CastResponse();
string castUrl = ClientAPIUtils.apiUrl + "shows/" + showid + "/cast";
res.CastlistResponse = JsonConvert.DeserializeObject<List<Cast>>(ClientAPIUtils.GetDataFromUrl(castUrl));
return res;
}
All the Calls should be made , but I am not sure where they are getting aborted and even please let me know how to check the rate of calls being made.
I'm assuming that your goal is to process all data about shows but no more than 20 at once.
For that kind of task you should probably use ThreadPool and limit maximum number of concurrent threads using SetMaxThreads.
https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool?view=netframework-4.7.2
You have to make sure that collection that you are using to store your results is thread-safe.
showCast.showCastList = new List<ShowData>();
I don't think that standard List is thread-safe. Thread-safe collection is ConcurrentBag (there are others as well). You can make standard list thread-safe but it requires more code. After you are done processing and need to have results in list or array you can convert collection to desired type.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentbag-1?view=netframework-4.7.2
Now to usage of semaphore. What your semaphore is doing is ensuring that maximum 20 threads can be created at once. Assuming that this loop runs in your app main thread your semaphore has no purpose. To make it work you need to release semaphore once thread is completed; but you are calling thread Start() after calling Release(). That results in thread being executed outside "critical area".
using (Semaphore pool = new Semaphore(20, 20)) {
for (int i = 0; i < allShows.Shows.Length; i++) {
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((taskId) =>
{
showCast.showCastList.Add(MapResponse(allShows.Shows[i]));
pool.Release();
}));
t.Start(i);
}
}
I did not test this solution; additional problems might arise.
Another issue with this program is that it does not wait for all threads to complete. Once all threads are started; program will end. It is possible (and in your case I'm sure) that not all threads completed its operation; this is why ~240 data packets are done when program finishes.
thread.Join();
But if called right after Start() it will stop main thread until it is completed so to keep program concurrent you need to create a list of threads and Join() them at the end of program. It is not the best solution. How to wait on all threads that program can add to ThreadPool
Wait until all threads finished their work in ThreadPool
As final note you cannot access loop counter like that. Final value of loop counter is evaluated later and with test I ran; code has tendency to process odd records twice and skip even. This is happening because loop increases counter before previous thread is executed and causes to access elements outside bounds of array.
Possible solution to that is to create method that will create thread. Having it in separate method will evaluate allShows.Shows[i] to show before next loop pass.
public void CreateAndStartThread(Show show, Semaphore pool, ShowCasts showCast)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((s) => {
showCast.showCastList.Add(MapResponse((Show)s));
pool.Release();
}));
t.Start(show);
}
Concurrent programming is tricky and I would highly recommend to do some exercises with examples on common pitfalls. Books on C# programming are sure to have a chapter or two on the topic. There are plenty of online courses and tutorials on this topic to learn from.
Edit:
Working solution. Still might have some issues.
public ShowCasts GetAllShowAndTheirCast()
{
ShowResponse allShows = GetAllShows();
ConcurrentBag<ShowData> result = new ConcurrentBag<ShowData>();
using (var countdownEvent = new CountdownEvent(allShows.Shows.Length))
{
using (Semaphore pool = new Semaphore(20, 20))
{
for (int i = 0; i < allShows.Shows.Length; i++)
{
CreateAndStartThread(allShows.Shows[i], pool, result, countdownEvent);
}
countdownEvent.Wait();
}
}
return new ShowCasts() { showCastList = result.ToList() };
}
public void CreateAndStartThread(Show show, Semaphore pool, ConcurrentBag<ShowData> result, CountdownEvent countdownEvent)
{
pool.WaitOne();
Thread t = new Thread(new ParameterizedThreadStart((s) =>
{
result.Add(MapResponse((Show)s));
pool.Release();
countdownEvent.Signal();
}));
t.Start(show);
}
I am starting TCPListener like this and when the job done I close the Socket.
I would like to know if the Thread which I start like this
ThreadPool.QueueUserWorkItem(ConnectClientsThredProc, args);
is going to destroy itself so I don't need any external control over it.
Would anyone so pleased to explain have I worry about it or don't.
Thank you!
class TCPListenerManager
{
TcpListener tcpListener;
HostListenerItem hostListener;
private bool _isServerWorking = false;
public TCPListenerManager(HostListenerItem hostListenerItem)
{
hostListener = hostListenerItem;
tcpListener = new TcpListener(IPAddress.Parse(hostListenerItem.IP4), hostListenerItem.Port);
var t = Task.Factory.StartNew(async () =>
{
await StartAsync(hostListenerItem.ClientsMax);
});
}
public async Task StartAsync(int clientsMax)
{
tcpListener.Start();
_isServerWorking = true;
for (int i = 0; i < clientsMax; i++)
{
if (_isServerWorking)
{
ServerConnectedEventArgs args = new ServerConnectedEventArgs();
args.TcpClient = await tcpListener.AcceptTcpClientAsync();
args.HostListener = hostListener;
OnServerConnected(args);
ThreadPool.QueueUserWorkItem(ConnectClientsThredProc, args);
}
}
}
private void ConnectClientsThredProc(object obj)
{
var args = (ServerConnectedEventArgs)obj;
if (args.TcpClient.Connected)
{
// Do some job and disconnect
args.TcpClient.Client.Close();
args.TcpClient.Client = null;
}
}
}
When ConnectClientsThredProc exits, thread is not "gone" but returned back to the pool (that's why thread pool exists in the first place). Anyway, you should not care about that indeed, unless you have long-running task performed in ConnectClientsThredProc. If it is long running - better not use thread pool thread, but start a new one (via Task.Factory.StartNew + TaskCreationOptions.LongRunning for example).
Also, you use Task.Factory, async\await, ThreadPool.QueueUserWorkItem, all that in a short piece of code, mixed together. Maybe you need to understand a bit better what are those tools and what are similarities and differences between them (especially async\await). For example, what is the reason for this:
var t = Task.Factory.StartNew(async () =>
{
await StartAsync(hostListenerItem.ClientsMax);
});
You start a task\thread, inside which you start yet another task and then wait for it to exit - makes little sense.
Instead of ThreadPool.QueueUserWorkItem you might use Task.Run with the same effect.
I'm trying to let my accounts do multiple logins with tasks. I am by no means an expert, I've only just started, but I'm stuck with the following problem I have.
For some reason the tasks keep looping, but they should not. I can't really figure out what the problem is, so I figured that someone on here might know the solution.
public async void Login()
{
for (int i = 0; i < objectsToCreate; i++)
{
try
{
this.Invoke((MethodInvoker)delegate()
{
MyEmail = listView1.Items[i].SubItems[0].Text;
MyPassword = listView1.Items[i].SubItems[1].Text;
MySecurity = listView1.Items[i].SubItems[2].Text;
});
var loginDetails = new LoginDetails(MyEmail, MyPassword, MySecurity, Platform.Ps3);
client[i] = new FutClient();
var loginResponse = await client[i].LoginAsync(loginDetails);
MessageBox.Show("Succesful login");
}
catch (Exception ex)
{
string foutMelding = ex.InnerException.ToString();
ListViewItem exception = new ListViewItem(time);
exception.SubItems.Add(foutMelding);
listView2.BeginInvoke(new MethodInvoker(() => listView2.Items.Add(exception)));
}
}
}
public void StartLogin()
{
Task[] tasks = new Task[objectsToCreate];
for (int i = 0; i < objectsToCreate; i++)
{
tasks[i] = new Task(() => Login());
}
foreach (Task task in tasks)
{
task.Start();
}
}
I call the StartLogin method with a button in my form. It then proceeds to login the accounts, but for some reason the tasks keep looping and I really can't figure out the reason, since I only just started with using Tasks. I would really appreciate it if someone could help me out.
It doesn't loop indefinitely - it executes exactly 16 times. This is because you essentially have a doubly nested for loop - one in your StartLogin method, and one in your Login method. Perhaps you aren't expecting the contents of your Login method to execute 4 times each time your Login method is called?
Based on the code you posted, I would expect the logic in the loop inside the Login() method to execute 16 times: 4 times for each time the Login() method itself is called, due to the for (int i = 0; i < objectsToCreate; i++) statement at the beginning of that method; and that, 4 times because you are creating 4 tasks to call the method.
It's hard to know what you meant to write, but I'm guessing you want to remove the loop from the Login() method itself. It looks like an artifact left over from a previous implementation attempt.
As an aside: it is a little odd to be mixing invocation of an async method with an explicit Task invocation of that method. It seems to me you could accomplish much the same result by simply calling the Login() method four times (minus the loop in the Login() method, of course).
Here's how I'd write the code:
public async void Login()
{
try
{
MyEmail = listView1.Items[i].SubItems[0].Text;
MyPassword = listView1.Items[i].SubItems[1].Text;
MySecurity = listView1.Items[i].SubItems[2].Text;
var loginDetails = new LoginDetails(MyEmail, MyPassword, MySecurity, Platform.Ps3);
client[i] = new FutClient();
var loginResponse = await client[i].LoginAsync(loginDetails);
MessageBox.Show("Succesful login");
}
catch (Exception ex)
{
string foutMelding = ex.InnerException.ToString();
ListViewItem exception = new ListViewItem(time);
exception.SubItems.Add(foutMelding);
listView2.Items.Add(exception);
}
}
public void StartLogin()
{
for (int i = 0; i < objectsToCreate; i++)
{
var _ = Login();
}
}
Note that, in this approach, since the Login() method is initially called from the UI thread (I presume...you didn't show the actual caller of the StartLogin() method, you don't need to use Invoke() or BeginInvoke() when accessing UI elements in that method.
(The var _ = is just to keep the compiler from complaining that I didn't await the async method. Here, that's on purpose :) ).
I am adding some data to a list and it might take a while to do this. Therefore i perform this action asynchronously. I do it like this:
ScanDelegate worker = StartScan;
AsyncCallback completedCallback = ScanCompletedCallback;
lock (_sync)
{
var async = AsyncOperationManager.CreateOperation(null);
worker.BeginInvoke(completedCallback, async);
}
The information added in StartScan() is correctly added to the list. When the scan is complete, i want to perform a different scan, depending on the data in the list. So i start the different scan in the ScanCompletedCallback() method. But at this point, my list is empty. Im guessing that this is because the callback method is invoked when the worker has been started, and not when it returns.
Is this true?
And if it is, how can i know when my worker has completed its tasks?
Edit: I can't get my head around this. It doesn't make sense. I came to think of the list i am adding to. I couldn't just add to it, i had to wrap it in a Dispatcher thread. This must be the problem, right? Is there a way i can make my Async method StartScan() wait for this Dispatcher ?
Thanks in advance!
StartScan()
private void StartScan()
{
//For testing
for (int t = 0; t < 1; t++)
{
var app2 = Application.Current;
if (app2 != null)
{
app2.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(AddComputerToList),
new ComputerModel()
{
HostName = "Andreas-PC",
IpAddress = "192.168.1.99",
ActiveDirectoryPath = "ikke i AD",
Name = "Andreas-PC",
OperatingSystem = "Microsoft Windows 7 Enterprise"
});
}
}
}
ScanCompletedCallback()
private void ScanCompletedCallback(IAsyncResult ar)
{
var worker = (ScanDelegate)((AsyncResult)ar).AsyncDelegate;
var async = (AsyncOperation)ar.AsyncState;
worker.EndInvoke(ar);
lock (_sync)
{
IsScanning = false;
}
var completedArgs = new AsyncCompletedEventArgs(null, false, null);
async.PostOperationCompleted(e => OnScanCompleted((AsyncCompletedEventArgs)e), completedArgs);
}
AddComputerToList()
private object AddComputerToList(Object objComputer)
{
var computer = objComputer as ComputerModel;
if (computer != null)
{
ComputersList.Add(computer);
OnPropertyChanged("ComputersList");
}
return null;
}
As a direct answer to your question the callback will occur on completion of ScanCompletedCallback.
If you have a list that you believe should have some data in it at this point then there appears to be something else wrong, posting some more code may help with this.