I have a requirement where I need to spawn multiple threads to execute a process. here the process is an exe. I'm facing a problem while multiple threads try to access the exe which is in a shared path.
I tried using a lock .even that din't help. Any help appreciated.Please find the code below.
Task t;
t = Task.Factory.StartNew(() =>
{
//lock (thisLock)
//{
// process = ProcessHelper.StartNew(objPSI.FileName, objPSI.Arguments, true, 5000);
// process.BeginOutputReadLine();
// process.OutputDataReceived += process_OutputDataReceived;
//}
process = ProcessHelper.StartNew(objPSI);
process.BeginOutputReadLine();
process.OutputDataReceived += process_OutputDataReceived;
//}
//var token = Task.Factory.CancellationToken;
//Task.Factory.StartNew(() =>
//{
// //this.label1.Text = "Task past first work section...";
//}, token, TaskCreationOptions.None, context);
}
)
.ContinueWith(_ =>
{
if (process.ExitCode != 0)
{
ErrorTexts.Add(process.StandardOutput.ReadToEnd());
}
else
{
ProgressText = "::: Migration Successful";
}
process.Close();
});
Related
I want to call qmodbusreply related monitoring function in the std thread.
void DigitalInputController::monitoring()
{
QModbusReply* reply = nullptr;
QModbusDataUnit d(QModbusDataUnit::Coils, 0, 8);
reply = m_pDevice->sendReadRequest(d, m_DeviceID);
if (reply)
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &DigitalInputController::receivedDigitalInputData);
}
else
{
delete reply;
}
}
}
The mainwindow source is as below.
:
:
std::thread th(&MainWindow::serialCommandQueueMonitoringThread, this);
th.detach();
for (int i=0; i<4; i++)
{
m_pPickingController[i]->m_pDigitalInputController->moveToThread(this->thread());
m_pPickingController[i]->moveToThread(this->thread());
}
:
:
void MainWindow::serialCommandQueueMonitoringThread()
{
while(!m_bCheckThreadStopFlag)
{
if (g_queueSerialCommandTypeInfo->size() > 0)
{
g_mutexSerialCommand->lock();
SerialCommandTypeInfo info = g_queueSerialCommandTypeInfo->dequeue();
g_mutexSerialCommand->unlock();
SerialCommandParamter p = info.parameter;
if (info.type == MONITORING_DIGITALINPUT)
{
m_pPickingController[p.objectIndex]->m_pDigitalInputController->monitoring();
}
}
QThread::msleep(20);
}
}
When executed, the following warning appears and the monitoring function cannot be called.
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QModbusRtuSerialMaster(0x2c56de33090), parent's thread is QThread(0x2c5670790b0), current thread is QThread(0x2c56ddb6290)
QObject::startTimer: Timers can only be used with threads started with QThread
How should I do?
I've created a custom GJS extension to connect into VPN. Basically it's a wrapper around a shell script, which is controlled from taskbar. There is a one issue, that after PC goes into suspend mode and back, extension is still displaying, that is disconnected, while it's still connected.
const GObject = imports.gi.GObject;
const St = imports.gi.St;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gettext = imports.gettext;
const _ = Gettext.gettext;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const MainLoop = imports.mainloop;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
let close_connection = `
pkexec kill -SIGINT $(pidof openconnect) 2>&1
`;
let create_connection = `
trap clean SIGINT
clean() {
pkexec kill -SIGINT $(pidof openconnect) 2>&1
}
vpn-ura-pke &
wait
`;
let _icon;
let _connectionSwitch;
let _last_connection = false;
let _already_running = false;
let _proc = null;
const iconsState = [
'network-vpn-acquiring-symbolic', // disconnected
'network-vpn-symbolic' // connected
];
function setConnectionState(connected) {
// prevent same notification changing
if (_last_connection == connected) return;
_icon.icon_name = iconsState[connected ? 1 : 0];
Main.notify('VPN URA', (connected ? 'connected' : 'disconnected'));
_last_connection = connected;
}
// read line callback
function onProcLine(stream, result) {
try {
let line = stream.read_line_finish_utf8(result)[0];
if (line !== null) {
// process read line
log("onProcLine:" + line);
// check connection status
if (line.includes('Connected as ')) setConnectionState(true);
else if(line.includes('Logout successful')) setConnectionState(false);
stream.read_line_async(0, null, onProcLine.bind(this));
}
} catch (ex) {
logError(ex);
}
}
// exec async process
async function execCheck(argv) {
_proc = new Gio.Subprocess({
argv: argv,
flags: (Gio.SubprocessFlags.STDIN_PIPE |
Gio.SubprocessFlags.STDOUT_PIPE |
Gio.SubprocessFlags.STDERR_PIPE)
});
_proc.init(null);
try {
let stdoutStream = new Gio.DataInputStream({
base_stream: _proc.get_stdout_pipe()
});
stdoutStream.read_line_async(
GLib.PRIORITY_DEFAULT,
null,
onProcLine.bind(this)
);
_proc.wait_check_async(null, (_proc, res) => {
try {
if (!_proc.wait_check_finish(res)) {
let status = _proc.get_exit_status();
setConnectionState(false);
if (status != 0) {
throw new Gio.IOErrorEnum({
code: Gio.io_error_from_errno(status),
message: GLib.strerror(status)
});
}
}
} catch (ex) {
setConnectionState(false);
logError(ex);
} finally {
_connectionSwitch.setToggleState(false);
}
});
} catch (ex) {
logError(ex);
}
}
const Indicator = GObject.registerClass(
class Indicator extends PanelMenu.Button {
toggleConnection(enabled) {
if (enabled) {
log("enable connection");
// start process
execCheck([
'bash',
'-c',
create_connection]
);
} else {
log("disable conenction");
// close running process
if (_proc) _proc.send_signal(2);
else if (_already_running) {
// kill process
Gio.Subprocess.new([
'bash',
'-c',
close_connection],
Gio.SubprocessFlags.STDOUT_PIPE
);
_already_running = false;
setConnectionState(false);
}
}
}
_init() {
super._init(0.0, _('VPN URA'));
// set icon
_icon = new St.Icon({
icon_name: iconsState[0],
style_class: 'system-status-icon'
});
this.add_child(_icon);
// toggle connection
_connectionSwitch = new PopupMenu.PopupSwitchMenuItem('Connection', false);
_connectionSwitch.connect('toggled', (_item, state) => {
this.toggleConnection(state);
});
this.menu.addMenuItem(_connectionSwitch);
// check if process is not already running
let [, , , status] = GLib.spawn_command_line_sync('pidof openconnect');
if (status == 0) {
_already_running = true;
_connectionSwitch.setToggleState(true);
setConnectionState(true);
}
}
});
class Extension {
constructor(uuid) {
this._uuid = uuid;
}
enable() {
_already_running = false;
this._indicator = new Indicator();
Main.panel.addToStatusArea(this._uuid, this._indicator, 1);
}
disable() {
_proc = null;
_connectionSwitch = null;
_last_connection = false;
_icon.destroy();
_icon = null;
this._indicator.destroy();
this._indicator = null;
}
}
function init(meta) {
return new Extension(meta.uuid);
}
Even if I added a case, where I was trying to use pidof to detect if process is running already. It caught only the case, when process was started outside from extension, but not the case, which I wanted.
How to bind into callback, which is fired up when session is restored? Or is there any another way to handle this?
Thanks,
Andy
I do also attempt to write a basic gnome extension for the same purpose.
Being very new to gjs coding, I found those answers regarding connection updating, in my research.
Hope some of it might help you :
Util.spawnCommandLine does not work on GNOME Shell extension
How to get OS name while writing gnome-extensions
GLib run command with root privileges
Running an asynchronous function in a GNOME extension
I have situation where i have to Use Task.Run In my ForEach loop
Requirement:
I'm going to be forced to manually kill thread
I have button where i can start and stop this Thread or Task.Run in For loop.
Problem
My problem is when i start the Task.Run method Its running but when i try to stop with using CancellationTokenSource or runningTaskThread.Abort(); it will not kill. its just stop when i start new Task.Run at that time it run with old thread so it become multiple thread every start process.
Code:
Below is my code for start Thread
var messages = rootObject.MultiQData.Messages.Where(m => m.TimeStamp > DateTime.Now).OrderBy(x => x.TimeStamp).ToList();
//Simulate MultiQ file in BackGroud
if (messages.Count > 0)
{
cancellationTokenSource = new CancellationTokenSource();
cancellationToken = cancellationTokenSource.Token;
Task.Factory.StartNew(
() =>
{
runningTaskThread = Thread.CurrentThread;
messages.ForEach(
m => SetUpTimer(m, rootObject.MultiQData.Connection.FleetNo));
}, cancellationToken);
}
For stop Task.Run
if (cancellationTokenSource != null)
{
if (cancellationToken.IsCancellationRequested)
return;
else
cancellationTokenSource.Cancel();
}
I have also use Thread with Thread.Abort but it is not working
Please Help to solve this issue
I got solution using timer.Stop(),timer.Dispose(). On creation of Thread i am calling SetUpTimer and this SetupTimer i have created multiple timer.
So on call of stop thread i have dispose timer and its work for me
For reference see below code
private void SetUpTimer(Message message, string fleetNo)
{
var ts = new MessageTimer();
var interval = (message.TimeStamp - DateTime.Now).TotalMilliseconds;
interval = interval <= 0 ? 100 : interval;
ts.MessageWrapper = new MessageWrapper(message, fleetNo);
ts.Interval = interval;
ts.Elapsed += ts_Elapsed;
ts.Start();
//Add timer in to the lost for disposing timer at time of stop Simulation
lsTimers.Add(ts);
}
private void StopTask()
{
try
{
// Attempt to cancel the task politely
if (cancellationTokenSource != null)
{
if (cancellationToken.IsCancellationRequested)
return;
else
cancellationTokenSource.Cancel();
}
//Stop All Timer
foreach (var timer in lsTimers)
{
timer.Stop();
timer.Dispose();
}
}
catch (Exception ex)
{
errorLogger.Error("Error while Stop simulation :", ex);
}
}
Suppose I have a BlockingCollection OutputQueue, which has many items. Current my code is:
public void Consumer()
{
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
PlayMessage(workItem);
Console.WriteLine("Works on {0}", workItem.TaskID);
OutLog.Write("Works on {0}", workItem.TaskID);
Thread.Sleep(500);
}
}
Now I want PlayMessage(workItem) running in the multiple tasks way because some workItem need more time, the others need less time. There are huge difference.
As for the method PlayMessage(workItem), it has a few service calls, play text to speech and some logging.
bool successRouting = serviceCollection.SvcCall_GetRoutingData(string[] params, out ex);
bool successDialingService = serviceCollection.SvcCall_GetDialingServiceData(string[] params, out excep);
PlayTTS(workItem.TaskType); // playing text to speech
So how to change my code?
What I thought was:
public async Task Consumer()
{
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
await PlayMessage(workItem);
Console.WriteLine("Works on {0}", workItem.TaskID);
OutLog.Write("Works on {0}", workItem.TaskID);
Thread.Sleep(500);
}
}
Since you want parallelism with your PlayMessage, i would suggest looking into TPL Dataflow, as it combines both parallel work with async, so you could await your work properly.
TPL Dataflow is constructed of Blocks, and each block has its own characteristics.
Some popular ones are:
ActionBlock<TInput>
TransformBlock<T, TResult>
I would construct something like the following:
var workItemBlock = new ActionBlock<WorkItem>(
workItem =>
{
PlayMessage(workItem);
Console.WriteLine("Works on {0}", workItem.TaskID);
OutLog.Write("Works on {0}", workItem.TaskID);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = // Set max parallelism as you wish..
});
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
workItemBlock.Post(workItem);
}
workItemBlock.Complete();
Here's another solution, not based on TPL Dataflow. It uses uses SemaphoreSlim to throttle the number of parallel playbacks (warning, untested):
public async Task Consumer()
{
var semaphore = new SemaphoreSlim(NUMBER_OF_PORTS);
var pendingTasks = new HashSet<Task>();
var syncLock = new Object();
Action<Task> queueTaskAsync = async(task) =>
{
// be careful with exceptions inside "async void" methods
// keep failed/cancelled tasks in the list
// they will be observed outside
lock (syncLock)
pendingTasks.Add(task);
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
await task;
}
catch
{
if (!task.IsCancelled && !task.IsFaulted)
throw;
// the error will be observed later,
// keep the task in the list
return;
}
finally
{
semaphore.Release();
}
// remove successfully completed task from the list
lock (syncLock)
pendingTasks.Remove(task);
};
foreach (var workItem in OutputQueue.GetConsumingEnumerable())
{
var item = workItem;
Func<Task> workAsync = async () =>
{
await PlayMessage(item);
Console.WriteLine("Works on {0}", item.TaskID);
OutLog.Write("Works on {0}", item.TaskID);
Thread.Sleep(500);
});
var task = workAsync();
queueTaskAsync(task);
}
await Task.WhenAll(pendingTasks.ToArray());
}
I have a timer to verify one condition every time and show pop up form only once if the condition is verified. I want to verify in parallel all instances, so i used parallel.for, but i have this error "Cross-thread operation not valid: Control 'CameraViewVS' accessed from a thread other than the thread it was created on." in line " frm.WindowState = FormWindowState.Normal;"
this is my code:
public void timer1_Tick(object source, EventArgs e)
{
Parallel.For(0, nbre, l =>
{
cameraInstanceList[l].Start();
if (cameraInstanceList[l].MoveDetection == true)
{
//show the the form S once
foreach (Form S in Application.OpenForms)
{
var frm = S as Formes.CameraViewVS;
if (frm != null && frm.IP == cameraInstanceList[l].adresse)
{
cameraInstanceList[l].MoveDetection = false;
frm.WindowState = FormWindowState.Normal;
frm.Activate();
return;
}
}
f1 = new Formes.CameraViewVS(cameraInstanceList[l],
adresseIPArray[l]);
f1.Show(this);
}
}
);
Most properties on WinForm object instances need to be accessed from the thread that they were created on. You can use the Control.InvokeRequired property to determine if you need to use the control (or form) Invoke method to execute the code on the UI thread.
It is also a good practise to create most WinForm controls on the main UI thread, and not on any thread pool threads. In WinForms applications, you can use the SynchronizationContext to ensure some code, such as creating a form, is called on the UI thread.
EDIT: changed so that the method doesn't return after movement detected.
public void timer1_Tick(object source, EventArgs e)
{
// assume this is being called on the UI thread, and save the thread synchronization context
var uiContext = SynchronizationContext.Current;
Parallel.For(0, nbre, l =>
{
while (true)
{
Thread.Sleep(250); // <--- sleep for 250 ms to avoid "busy" wait
cameraInstanceList[l].Start();
if (cameraInstanceList[l].MoveDetection == true)
{
// capture instances used in closures below
var cameraInstance = cameraInstanceList[l];
var ipAdresse = adresseIPArray[l];
//show the the form S once
foreach (Form S in Application.OpenForms)
{
var frm = S as Formes.CameraViewVS;
if (frm != null)
{
// create delegate to be invoked on form's UI thread.
var action = new Action(() =>
{
if (frm.IP == cameraInstance.adresse)
{
cameraInstance.MoveDetection = false;
frm.WindowState = FormWindowState.Normal;
frm.Activate();
}
};
if (frm.InvokeRequired)
frm.Invoke(action);
else
action();
continue; // <--- go back to the top of the while loop
// and wait for next detection
}
}
// create delegate to create new form on UI thread.
var createNewFormCallback = new SendOrPostCallback((o) =>
{
f1 = new Formes.CameraViewVS(cameraInstance, ipAdresse);
f1.Show(this);
};
// and invoke the delegate on the ui thread
uiContext.Send(createNewFormCallback, null);
}
}
}
);
}
Thomas is very close to right answer ,Because Every Control runs in a different thread .You should just write a code for context-switching of resources which is being used by Controls
Thread ..Don't worry you have a lot of facility for this in c sharp.Just use BeginInvoke and Invoke and i hope you would be able to resolve your problem.Write this in place of your old code block ..
var action = new Action(() =>
{
if (frm.IP == cameraInstance.adresse)
{
cameraInstance.MoveDetection = false;
frm.WindowState = FormWindowState.Normal;
frm.Activate();
}
};
if (frm.InvokeRequired)
frm.BeginInvoke(action);
else
frm.Invoke(action);