How can I correct the error "Cross-thread operation not valid"? - multithreading

This following code gives me the error below . I think I need "InvokeRequired" . But I don't understand how can I use?
error:Cross-thread operation not valid: Control 'statusBar1' accessed from a thread other than the thread it was created on.
the code :
public void CalculateGeneration(int nPopulation, int nGeneration)
{
int _previousFitness = 0;
Population TestPopulation = new Population();
for (int i = 0; i < nGeneration; i++)
{
if (_threadFlag)
break;
TestPopulation.NextGeneration();
Genome g = TestPopulation.GetHighestScoreGenome();
if (i % 100 == 0)
{
Console.WriteLine("Generation #{0}", i);
if ( ToPercent(g.CurrentFitness) != _previousFitness)
{
Console.WriteLine(g.ToString());
_gene = g;
statusBar1.Text = String.Format("Current Fitness = {0}", g.CurrentFitness.ToString("0.00"));
this.Text = String.Format("Sudoko Grid - Generation {0}", i);
Invalidate();
_previousFitness = ToPercent(g.CurrentFitness);
}
if (g.CurrentFitness > .9999)
{
Console.WriteLine("Final Solution at Generation {0}", i);
statusBar1.Text = "Finished";
Console.WriteLine(g.ToString());
break;
}
}
}
}

Easiest for reusability is to add a helper function like:
void setstatus(string txt)
{
Action set = () => statusBar1.Text = txt;
statusBar1.Invoke(set);
}
Or with the invokerequired check first:
delegate void settextdelegate(string txt);
void setstatus(string txt)
{
if (statusBar1.InvokeRequired)
statusBar1.Invoke(new settextdelegate(setstatus), txt);
else
statusBar1.Text = txt;
}
Either way the status can then be set like
setstatus("Finished");
For completeness I should add that even better would be to keep your calculating logic separated from your form and raise a status from within your calculating functionality that can be hanled by the form, but that could be completely out of scope here.

Related

scanner input that can stop loop anytime?

I'm making a clock and I want a specific input to be able to stop it.
Any ideas?
Here's my code:
public static void main(String[] args) {
//...
Scanner input = new Scanner(System.in);
//...
int s = 0;
int m = 0;
int h = 0;
clock: // label to break a outer most loop
for(int i = 0; i<2; i++) {
on = Boolean.parseBoolean(onValue[i]);
while (on = true) {
for (i=1; i<=60; i++) {
s++;
if(input2check.compareTo("") == 0) {
on = Boolean.parseBoolean(onValue[1]);
break clock;
}
if (s == 60) {
s = 0;
}
System.out.println(s + " sec" );
}
}
}
}
First idea: do the Scanner in a separate thread
As you've noticed, Scanner.nextLine blocks until the user has input something and pressed Enter. We can ignore this problem if our clock does not run in the same thread as the Scanner loop. Let's use a daemon thread for reading user input.
I've picked the word "off" as stopping input from the user.
import java.util.Scanner;
public class Clock1 {
private static volatile boolean on = true;
public static void main(String[] args) throws InterruptedException {
int s = 0, m = 0, h = 0;
Thread t = new Thread(() -> {
try (Scanner scan = new Scanner(System.in)) {
while (on) {
String input = scan.nextLine();
if (input == null)
continue;
if ("off".equalsIgnoreCase(input.trim())) {
on = false;
}
}
}
});
t.setName("console");
t.setDaemon(true);
t.start();
clock: for (int i = 0; i < 2; i++) { //Why this loop ?
long prevTime = System.nanoTime();
long diff;
while (on) {
if (++s % 60 == 0) {
s = 0;
if (++m % 60 == 0) {
m = 0;
++h;
}
}
do {
diff = System.nanoTime() - prevTime;
Thread.sleep(Math.min(1000 - diff / 1_000_000L, 100));
} while (on && diff < 1_000_000_000L);
if (!on)
break clock;
prevTime = System.nanoTime();
System.out.println(String.format("%02d:%02d:%02d", h, m, s));
}
}
System.out.println("Clock stopped");
}
}
You need to be aware that timing a clock with Thread.sleep is inaccurate, though. But it may be enough for your problem...
I tried to compensate for this using several checks for System.nanoTime per second, but accurate timing would require a more complex algorithm. It also allows for about immediate reaction to user input.
Second idea: use a BufferedReader rather than a Scanner
Using a BufferedReader allows us to avoid blocking execution while we check if the buffer is ready, and then only read user input when they've pressed Enter, thus bypassing the problem with Scanner.nextLine.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class Clock2 {
private static volatile boolean on = true;
public static void main(String[] args) throws InterruptedException, IOException {
int s = 0, m = 0, h = 0;
try (BufferedReader rdr = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
clock: for (int i = 0; i < 2; i++) { // Why this loop ?
long prevTime = System.nanoTime();
long diff;
while (on) {
if (++s % 60 == 0) {
s = 0;
if (++m % 60 == 0) {
m = 0;
++h;
}
}
do {
diff = System.nanoTime() - prevTime;
Thread.sleep(Math.min(1000 - diff / 1_000_000L, 100));
String line;
while (on && rdr.ready() && (line = rdr.readLine()) != null) {
if (line.trim().equalsIgnoreCase("off"))
on = false;
}
} while (on && diff < 1_000_000_000L);
if (!on)
break clock;
prevTime = System.nanoTime();
System.out.println(String.format("%02d:%02d:%02d", h, m, s));
}
}
}
System.out.println("Clock stopped");
}
}
Third idea: use a ScheduledExecutor
This time, the clock is timed by a ScheduledExecutor that executes the increment loop once per second in a separate thread as the main program.
Accumulated values had to be stored in a class, so I also implemented AutoCloseable with class Clock3 to ease shutting down the executor when the clock stops.
User input is read in a loop in the main thread using a Scanner until we hit the word "off".
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Clock3 implements AutoCloseable {
private static volatile boolean on = true;
private ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
private int s = 0, m = 0, h = 0;
public static void main(String[] args) throws Exception {
try (Clock3 clock = new Clock3()) {
try (Scanner scan = new Scanner(System.in)) {
while (on) {
String input = scan.nextLine();
if (input == null)
continue;
if ("off".equalsIgnoreCase(input.trim())) {
on = false;
}
}
}
}
System.out.println("Clock stopped");
}
public Clock3() {
exec.scheduleAtFixedRate(() -> {
if (++s % 60 == 0) {
s = 0;
if (++m % 60 == 0) {
m = 0;
++h;
}
}
if (on)
System.out.println(String.format("%02d:%02d:%02d", h, m, s));
}, 0, 1, TimeUnit.SECONDS);
}
#Override
public void close() throws Exception {
exec.shutdownNow();
}
}
I don't know how accurate this scheduling is guaranteed to be. From what I can read from documentation for ScheduledExecutorService.scheduleAtFixedRate:
If any execution of this task takes longer than its period, then subsequent executions may start late.
Which will never be the case with this small increment algorithm.
There are probably better ways of scheduling that however, but that was not the point of your question...

Problems in using SwingWorker class for reading a file and implementing a JProgressBar

Note: This question may look like a repetition of several question posted on the forum, but I am really stuck on this problem from quite some time and I am not able to solve this issue using the solutions posted for similar questions. I have posted my code here and need help to proceed further
So, here is my issue:
I am writing a Java GUI application which loads a file before performing any processing. There is a waiting time on an average of about 10-15 seconds during which the file is parsed. After this waiting time, what I get see on the GUI is,
The parsed file in the form of individual leaves in the JTree in a Jpanel
Some header information (example: data range) in two individual JTextField
A heat map generated after parsing the data in a different JPanel on the GUI.
The program connects to R to parse the file and read the header information.
Now, I want to use swing worker to put the file reading process on a different thread so that it does not block the EDT. I am not sure how I can build my SwingWorker class so that the process is done in the background and the results for the 3 components are displayed when the process is complete. And, during this file reading process I want to display a JProgressBar.
Here is the code which does the whole process, starting from selection of the file selection menu item. This is in the main GUI method.
JScrollPane spectralFilesScrollPane;
if ((e.getSource() == OpenImagingFileButton) || (e.getSource() == loadRawSpectraMenuItem)) {
int returnVal = fcImg.showOpenDialog(GUIMain.this);
// File chooser
if (returnVal == JFileChooser.APPROVE_OPTION) {
file = fcImg.getSelectedFile();
//JTree and treenode creation
DefaultMutableTreeNode root = new DefaultMutableTreeNode(file);
rawSpectraTree = new JTree(root);
DefaultTreeModel model = (DefaultTreeModel) rawSpectraTree.getModel();
try {
// R connection
rc = new RConnection();
final String inputFileDirectory = file.getParent();
System.out.println("Current path: " + currentPath);
rc.assign("importImagingFile", currentPath.concat("/importImagingFile.R"));
rc.eval("source(importImagingFile)");
rc.assign("currentWorkingDirectory", currentPath);
rc.assign("inputFileDirectory", inputFileDirectory);
rawSpectrumObjects = rc.eval("importImagingFile(inputFileDirectory,currentWorkingDirectory)");
rc.assign("plotAverageSpectra", currentPath.concat("/plotAverageSpectra.R"));
rc.eval("source(plotAverageSpectra)");
rc.assign("rawSpectrumObjects", rawSpectrumObjects);
REXP averageSpectraObject = rc.eval("plotAverageSpectra(rawSpectrumObjects)");
rc.assign("AverageMassSpecObjectToSpectra", currentPath.concat("/AverageMassSpecObjectToSpectra.R"));
rc.eval("source(AverageMassSpecObjectToSpectra)");
rc.assign("averageSpectraObject", averageSpectraObject);
REXP averageSpectra = rc.eval("AverageMassSpecObjectToSpectra(averageSpectraObject)");
averageSpectraMatrix = averageSpectra.asDoubleMatrix();
String[] spectrumName = new String[rawSpectrumObjects.asList().size()];
for (int i = 0; i < rawSpectrumObjects.asList().size(); i++) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Spectrum_" + (i + 1));
model.insertNodeInto(node, root, i);
}
// Expand all the nodes of the JTree
for(int i=0;i< model.getChildCount(root);++i){
rawSpectraTree.expandRow(i);
}
DefaultMutableTreeNode firstLeaf = ((DefaultMutableTreeNode)rawSpectraTree.getModel().getRoot()).getFirstLeaf();
rawSpectraTree.setSelectionPath(new TreePath(firstLeaf.getPath()));
updateSpectralTableandChartRAW(firstLeaf);
// List the min and the max m/z of in the respective data fields
rc.assign("dataMassRange", currentPath.concat("/dataMassRange.R"));
rc.eval("source(dataMassRange)");
rc.assign("rawSpectrumObjects", rawSpectrumObjects);
REXP massRange = rc.eval("dataMassRange(rawSpectrumObjects)");
double[] massRangeValues = massRange.asDoubles();
minMzValue = (float)massRangeValues[0];
maxMzValue = (float)massRangeValues[1];
GlobalMinMz = minMzValue;
GlobalMaxMz = maxMzValue;
// Adds the range values to the jTextField
minMz.setText(Float.toString(minMzValue));
minMz.validate();
minMz.repaint();
maxMz.setText(Float.toString(maxMzValue));
maxMz.validate();
maxMz.repaint();
// Update status bar with the uploaded data details
statusLabel.setText("File name: " + file.getName() + " | " + "Total spectra: " + rawSpectrumObjects.asList().size() + " | " + "Mass range: " + GlobalMinMz + "-" + GlobalMaxMz);
// Generates a heatmap
rawIntensityMap = gim.generateIntensityMap(rawSpectrumObjects, currentPath, minMzValue, maxMzValue, Gradient.GRADIENT_Rainbow, "RAW");
rawIntensityMap.addMouseListener(this);
rawIntensityMap.addMouseMotionListener(this);
imagePanel.add(rawIntensityMap, BorderLayout.CENTER);
coordinates = new JLabel();
coordinates.setBounds(31, 31, rawIntensityMap.getWidth() - 31, rawIntensityMap.getHeight() - 31);
panelRefresh(imagePanel);
tabbedSpectralFiles.setEnabledAt(1, false);
rawSpectraTree.addTreeSelectionListener(new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent e) {
try {
DefaultMutableTreeNode selectedNode =
(DefaultMutableTreeNode) rawSpectraTree.getLastSelectedPathComponent();
int rowCount = listTableModel.getRowCount();
for (int l = 0; l < rowCount; l++) {
listTableModel.removeRow(0);
}
updateSpectralTableandChartRAW(selectedNode);
} catch (RserveException e2) {
e2.printStackTrace();
} catch (REXPMismatchException e1) {
e1.printStackTrace();
}
}
});
spectralFilesScrollPane = new JScrollPane();
spectralFilesScrollPane.setViewportView(rawSpectraTree);
spectralFilesScrollPane.setPreferredSize(rawFilesPanel.getSize());
rawFilesPanel.add(spectralFilesScrollPane);
tabbedSpectralFiles.validate();
tabbedSpectralFiles.repaint();
rawImage.setEnabled(true);
peakPickedImage.setEnabled(false);
loadPeakListMenuItem.setEnabled(true); //active now
loadPeaklistsButton.setEnabled(true); //active now
propertiesMenuItem.setEnabled(true); // active now
propertiesButton.setEnabled(true); //active now
} catch (RserveException e1) {
JOptionPane.showMessageDialog(this,
"There was an error in the R connection. Please try again!", "Error",
JOptionPane.ERROR_MESSAGE);
} catch (REXPMismatchException e1) {
JOptionPane.showMessageDialog(this,
"Operation requested is not supported by the given R object type. Please try again!", "Error",
JOptionPane.ERROR_MESSAGE);
}
// hideProgress();
}
}
I tried creating a SwingWorker class, but I am totally confused how I can get all the three outputs on the GUI, plus have a progress bar. It is not complete, but I don't know how to proceed further.
public class FileReadWorker extends SwingWorker<REXP, String>{
private static void failIfInterrupted() throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException("Interrupted while loading imaging file!");
}
}
// The file that is being read
private final File fileName;
private JTree rawSpectraTree;
private RConnection rc;
private REXP rawSpectrumObjects;
private double[][] averageSpectraMatrix;
private Path currentRelativePath = Paths.get("");
private final String currentPath = currentRelativePath.toAbsolutePath().toString();
final JProgressBar progressBar = new JProgressBar();
// public FileReadWorker(File fileName)
// {
// this.fileName = fileName;
// System.out.println("I am here");
// }
public FileReadWorker(final JProgressBar progressBar, File fileName) {
this.fileName = fileName;
addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
});
progressBar.setVisible(true);
progressBar.setStringPainted(true);
progressBar.setValue(0);
setProgress(0);
}
#Override
protected REXP doInBackground() throws Exception {
System.out.println("I am here... in background");
DefaultMutableTreeNode root = new DefaultMutableTreeNode(fileName);
rawSpectraTree = new JTree(root);
DefaultTreeModel model = (DefaultTreeModel) rawSpectraTree.getModel();
rc = new RConnection();
final String inputFileDirectory = fileName.getParent();
rc.assign("importImagingFile", currentPath.concat("/importImagingFile.R"));
rc.eval("source(importImagingFile)");
rc.assign("currentWorkingDirectory", currentPath);
rc.assign("inputFileDirectory", inputFileDirectory);
rawSpectrumObjects = rc.eval("importImagingFile(inputFileDirectory,currentWorkingDirectory)");
rc.assign("plotAverageSpectra", currentPath.concat("/plotAverageSpectra.R"));
rc.eval("source(plotAverageSpectra)");
rc.assign("rawSpectrumObjects", rawSpectrumObjects);
REXP averageSpectraObject = rc.eval("plotAverageSpectra(rawSpectrumObjects)");
rc.assign("AverageMassSpecObjectToSpectra", currentPath.concat("/AverageMassSpecObjectToSpectra.R"));
rc.eval("source(AverageMassSpecObjectToSpectra)");
rc.assign("averageSpectraObject", averageSpectraObject);
REXP averageSpectra = rc.eval("AverageMassSpecObjectToSpectra(averageSpectraObject)");
averageSpectraMatrix = averageSpectra.asDoubleMatrix();
for (int i = 0; i < rawSpectrumObjects.asList().size(); i++) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Spectrum_" + (i + 1));
model.insertNodeInto(node, root, i);
}
// Expand all the nodes of the JTree
for(int i=0;i< model.getChildCount(root);++i){
rawSpectraTree.expandRow(i);
}
return averageSpectra;
}
#Override
public void done() {
setProgress(100);
progressBar.setValue(100);
progressBar.setStringPainted(false);
progressBar.setVisible(false);
}
}
Any help would be very much appreciated.

How to avoid java.util.NoSuchElementException

The code below is giving me the error java.util.NoSuchElementException right after I Ctrl+Z
to indicate that the user input is complete. By the looks of it seems as if it does not know how to just end one method without messing with the other scanner object.
I try the hasNext method and I ended up with an infinite loop, either way is not working. As a requirement for this assignment I need to be able to tell the user to use Ctrl+Z or D depending on the operating system. Also I need to be able to read from a text file and save the final tree to a text file please help.
/* sample input:
CSCI3320
project
personal
1 HW1
1 HW2
1 2 MSS.java
2 p1.java
*/
import java.util.Scanner;
import java.util.StringTokenizer;
public class Directory {
private static TreeNode root = new TreeNode("/", null, null);
public static void main(String[] args) {
userMenu();
System.out.println("The directory is displayed as follows:");
root.listAll(0);
}
private static void userMenu(){ //Displays users menu
Scanner userInput = new Scanner(System.in);//Scanner option
int option = 0;
do{ //I believe the problem is here since I am not using userInput.Next()
System.out.println("\n 1. add files from user inputs ");
System.out.println("\n 2. display the whole directory ");
System.out.println("\n 3. display the size of directory ");
System.out.println("\n 0. exit");
System.out.println("\n Please give a selection [0-3]: ");
option = userInput.nextInt();
switch(option){
case 1: addFileFromUser();
break;
case 2: System.out.println("The directory is displayed as follows:");
root.listAll(0);
break;
case 3: System.out.printf("The size of the directory is %d.\n", root.size());
break;
default:
break;
}
}while( option !=0);
userInput.close();
}
private static void addFileFromUser() {
System.out.println("To terminate inp1ut, type the correct end-of-file indicator ");
System.out.println("when you are prompted to enter input.");
System.out.println("On UNIX/Linux/Mac OS X type <ctrl> d");
System.out.println("On Windows type <ctrl> z");
Scanner input = new Scanner(System.in);
while (input.hasNext()) { //hasNext being used Crtl Z is required to break
addFileIntoDirectory(input); // out of the loop.
}
input.close();
}
private static void addFileIntoDirectory(Scanner input) {
String line = input.nextLine();
if (line.trim().equals("")) return;
StringTokenizer tokens = new StringTokenizer(line);
int n = tokens.countTokens() - 1;
TreeNode p = root;
while (n > 0 && p.isDirectory()) {
int a = Integer.valueOf( tokens.nextToken() );
p = p.getFirstChild();
while (a > 1 && p != null) {
p = p.getNextSibling();
a--;
}
n--;
}
String name = tokens.nextToken();
TreeNode newNode = new TreeNode(name, null, null);
if (p.getFirstChild() == null) {
p.setFirstChild(newNode);
}
else {
p = p.getFirstChild();
while (p.getNextSibling() != null) {
p = p.getNextSibling();
}
p.setNextSibling(newNode);
}
}
private static class TreeNode {
private String element;
private TreeNode firstChild;
private TreeNode nextSibling;
public TreeNode(String e, TreeNode f, TreeNode s) {
setElement(e);
setFirstChild(f);
setNextSibling(s);
}
public void listAll(int i) {
for (int k = 0; k < i; k++) {
System.out.print('\t');
}
System.out.println(getElement());
if (isDirectory()) {
TreeNode t = getFirstChild();
while (t != null) {
t.listAll(i+1);
t = t.getNextSibling();
}
}
}
public int size() {
int s = 1;
if (isDirectory()) {
TreeNode t = getFirstChild();
while (t != null) {
s += t.size();
t = t.getNextSibling();
}
}
return s;
}
public void setElement(String e) {
element = e;
}
public String getElement() {
return element;
}
public boolean isDirectory() {
return getFirstChild() != null;
}
public void setFirstChild(TreeNode f) {
firstChild = f;
}
public TreeNode getFirstChild() {
return firstChild;
}
public void setNextSibling(TreeNode s) {
nextSibling = s;
}
public TreeNode getNextSibling() {
return nextSibling;
}
}
}
Exception Details:
/*Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at Directory.userMenu(Directory.java:36)
at Directory.main(Directory.java:21)*/
Your problem is this line:
option = userInput.nextInt(); //line 24
If you read the Javadoc, you will find that the nextInt() method can throw a NoSuchElementException if the input is exhausted. In other words, there is no next integer to get. Why is this happening in your code? Because you this line is in a loop once that first iteration completes (on the outer while loop) your initial input selection has been consumed. Since this is a homework, I am not going to write the code. But, if you remove the loop, you know this works at least once. Once you try to loop, it breaks. So I will give you these hints:
Change the do/while to a while loop.
Prompt the user once outside the loop.
Recreate the prompt and recapture the user input inside the loop.
For example, the code below can be used for the basis of your outer loop.
import java.util.Scanner;
public class GuessNumberGame {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Guess the secret number: (Hint: the secret number is 1)");
int guess = input.nextInt();
while (guess != 1) {
System.out.println("Wrong guess. Try again: ");
guess = input.nextInt();
}
System.out.println("Success");
input.close();
}
}
The reason why this works is because I don't reuse the same, exhausted, scanner input object to get the next integer. In your example, the initial input is inside the loop. The second time around, that input has already been consumed. Follow this pattern and you should be able to complete your assignment.

Why is parallel.Invoke not working in this case

I have an array of files like this..
string[] unZippedFiles;
the idea is that I want to parse these files in paralle. As they are parsed a record gets placed on a concurrentbag. As record is getting placed I want to kick of the update function.
Here is what I am doing in my Main():
foreach(var file in unZippedFiles)
{ Parallel.Invoke
(
() => ImportFiles(file),
() => UpdateTest()
);
}
this is what the code of Update loooks like.
static void UpdateTest( )
{
Console.WriteLine("Updating/Inserting merchant information.");
while (!merchCollection.IsEmpty || producingRecords )
{
merchant x;
if (merchCollection.TryTake(out x))
{
UPDATE_MERCHANT(x.m_id, x.mInfo, x.month, x.year);
}
}
}
This is what the import code looks like. It's pretty much a giant string parser.
System.IO.StreamReader SR = new System.IO.StreamReader(fileName);
long COUNTER = 0;
StringBuilder contents = new StringBuilder( );
string M_ID = "";
string BOF_DELIMITER = "%%MS_SKEY_0000_000_PDF:";
string EOF_DELIMITER = "%%EOF";
try
{
record_count = 0;
producingRecords = true;
for (COUNTER = 0; COUNTER <= SR.BaseStream.Length - 1; COUNTER++)
{
if (SR.EndOfStream)
{
break;
}
contents.AppendLine(Strings.Trim(SR.ReadLine()));
contents.AppendLine(System.Environment.NewLine);
//contents += Strings.Trim(SR.ReadLine());
//contents += Strings.Chr(10);
if (contents.ToString().IndexOf((EOF_DELIMITER)) > -1)
{
if (contents.ToString().StartsWith(BOF_DELIMITER) & contents.ToString().IndexOf(EOF_DELIMITER) > -1)
{
string data = contents.ToString();
M_ID = data.Substring(data.IndexOf("_M") + 2, data.Substring(data.IndexOf("_M") + 2).IndexOf("_"));
Console.WriteLine("Merchant: " + M_ID);
merchant newmerch;
newmerch.m_id = M_ID;
newmerch.mInfo = data.Substring(0, (data.IndexOf(EOF_DELIMITER) + 5));
newmerch.month = DateTime.Now.AddMonths(-1).Month;
newmerch.year = DateTime.Now.AddMonths(-1).Year;
//Update(newmerch);
merchCollection.Add(newmerch);
}
contents.Clear();
//GC.Collect();
}
}
SR.Close();
// UpdateTest();
}
catch (Exception ex)
{
producingRecords = false;
}
finally
{
producingRecords = false;
}
}
the problem i am having is that the Update runs once and then the importfile function just takes over and does not yield to the update function. Any ideas on what am I doing wrong would be of great help.
Here's my stab at fixing your thread synchronisation. Note that I haven't changed any of the code from the functional standpoint (with the exception of taking out the catch - it's generally a bad idea; exceptions need to be propagated).
Forgive if something doesn't compile - I'm writing this based on incomplete snippets.
Main
foreach(var file in unZippedFiles)
{
using (var merchCollection = new BlockingCollection<merchant>())
{
Parallel.Invoke
(
() => ImportFiles(file, merchCollection),
() => UpdateTest(merchCollection)
);
}
}
Update
private void UpdateTest(BlockingCollection<merchant> merchCollection)
{
Console.WriteLine("Updating/Inserting merchant information.");
foreach (merchant x in merchCollection.GetConsumingEnumerable())
{
UPDATE_MERCHANT(x.m_id, x.mInfo, x.month, x.year);
}
}
Import
Don't forget to pass in merchCollection as a parameter - it should not be static.
System.IO.StreamReader SR = new System.IO.StreamReader(fileName);
long COUNTER = 0;
StringBuilder contents = new StringBuilder( );
string M_ID = "";
string BOF_DELIMITER = "%%MS_SKEY_0000_000_PDF:";
string EOF_DELIMITER = "%%EOF";
try
{
record_count = 0;
for (COUNTER = 0; COUNTER <= SR.BaseStream.Length - 1; COUNTER++)
{
if (SR.EndOfStream)
{
break;
}
contents.AppendLine(Strings.Trim(SR.ReadLine()));
contents.AppendLine(System.Environment.NewLine);
//contents += Strings.Trim(SR.ReadLine());
//contents += Strings.Chr(10);
if (contents.ToString().IndexOf((EOF_DELIMITER)) > -1)
{
if (contents.ToString().StartsWith(BOF_DELIMITER) & contents.ToString().IndexOf(EOF_DELIMITER) > -1)
{
string data = contents.ToString();
M_ID = data.Substring(data.IndexOf("_M") + 2, data.Substring(data.IndexOf("_M") + 2).IndexOf("_"));
Console.WriteLine("Merchant: " + M_ID);
merchant newmerch;
newmerch.m_id = M_ID;
newmerch.mInfo = data.Substring(0, (data.IndexOf(EOF_DELIMITER) + 5));
newmerch.month = DateTime.Now.AddMonths(-1).Month;
newmerch.year = DateTime.Now.AddMonths(-1).Year;
//Update(newmerch);
merchCollection.Add(newmerch);
}
contents.Clear();
//GC.Collect();
}
}
SR.Close();
// UpdateTest();
}
finally
{
merchCollection.CompleteAdding();
}
}

C# - Trying to create a threaded process using a function that has as Action as a parameter

This is a project I'm doing for my own amusement.
I started out wanting to experiment with combination and permutations. In a console application I have the following code
public static void Save(string newWord)
{
using (var db = new MyDataContext())
{
var w = new Word {word = newWord};
db.Words.InsertOnSubmit(w);
db.SubmitChanges();
}
}
static void Main(string[] args)
{
var letters = new[] { 'A', 'B', 'C', '1', '2', '3'};
for (var i = 2; i < 10; i++)
{
letters.GetPermutations(a => Save(string.Join(string.Empty, a.ToArray())), i, true);
}
}
In an extension class, I have the code to generate the combinations. I found the code for the combinations here (http://blog.noldorin.com/2010/05/combinatorics-in-csharp/) for those wanting to review that.
public static void GetCombinations<T>(this IList<T> list, Action<IList<T>> action, int? resultSize = null, bool withRepetition = false)
{
if (list == null)
throw new ArgumentNullException("list");
if (action == null)
throw new ArgumentNullException("action");
if (resultSize.HasValue && resultSize.Value <= 0)
throw new ArgumentException(errorMessageValueLessThanZero, "resultSize");
var result = new T[resultSize.HasValue ? resultSize.Value : list.Count];
var indices = new int[result.Length];
for (int i = 0; i < indices.Length; i++)
indices[i] = withRepetition ? -1 : indices.Length - i - 2;
int curIndex = 0;
while (curIndex != -1)
{
indices[curIndex]++;
if (indices[curIndex] == (curIndex == 0 ? list.Count : indices[curIndex - 1] + (withRepetition ? 1 : 0)))
{
indices[curIndex] = withRepetition ? -1 : indices.Length - curIndex - 2;
curIndex--;
}
else
{
result[curIndex] = list[indices[curIndex]];
if (curIndex < indices.Length - 1)
curIndex++;
else
action(result);
}
}
}
Then I thought it would be cool to calculate the combinations for all charaters in a list, each in its own thread. So in my for/next loop, I tried
Thread t = new Thread(letters.GetPermutations(a => Save(string.Join(string.Empty, a.ToArray())), i, true));
But apparently, the Action that is being passed in, the call to the 'Save' function, is not liked in the Thread. If someone could give me a nudge in the right direction, I'd appreciate it.
Thanks,
Andy
The Thread constructor is looking for a delegate but you're appearing to pass a value instead. Try wrapping it in an ThreadStart delegate.
ThreadStart del = () => letters.GetPermutations(a => Save(string.Join(string.Empty, a.ToArray())), i, true);
Thread t = new Thread(del);
t.Start();

Resources