我对编程很陌生,希望你能帮助我。我的任务是制作3个不同的线程,它们读取带有给定int的txt文件。然后必须打印出这些值的总和。我想从我制作的三个线程中访问int。我怎么能这样做?
这是我的一些代码:
class Program
{
static void Main()
{
Thread t1 = new Thread(ReadFile1);
Thread t2 = new Thread(ReadFile2);
Thread t3 = new Thread(ReadFile3);
t1.Start();
t2.Start();
t3.Start();
System.Console.WriteLine("Sum: ");
Console.WriteLine();
Console.WriteLine("");
System.Console.ReadKey();
}
public static void ReadFile1()
{
System.IO.StreamReader file1 = new System.IO.StreamReader({FILEDESTINATION});
int x = int.Parse(file1.ReadLine());
}
答案 0 :(得分:2)
.NET中的任务系统使这很容易。在几乎所有情况下,您都应该更喜欢原始线程。以你的例子:
var t1 = Task.Run(() => ReadFile(path1));
var t2 = Task.Run(() => ReadFile(path2));
var t3 = Task.Run(() => ReadFile(path3));
Console.WriteLine("Sum: {0}", t1.Result + t2.Result + t3.Result);
static int ReadFile(string path) {
using(var file = new StreamReader(path))
return int.Parse(file.ReadLine());
}
答案 1 :(得分:1)
试试这个......
class Program
{
static int? Sum = null;
static Object lockObject = new Object();
static void Main()
{
Thread t1 = new Thread(ReadFile);
Thread t2 = new Thread(ReadFile);
Thread t3 = new Thread(ReadFile);
t1.Start(@"C:\Users\Mike\Documents\SomeFile1.txt");
t2.Start(@"C:\Users\Mike\Documents\SomeFile2.txt");
t3.Start(@"C:\Users\Mike\Documents\SomeFile3.txt");
t1.Join();
t2.Join();
t3.Join();
if (Sum.HasValue)
{
System.Console.WriteLine("Sum: " + Sum.ToString());
}
else
{
System.Console.WriteLine("No values were successfully retrieved from the files!");
}
Console.WriteLine("");
Console.Write("Press Enter to Quit");
System.Console.ReadLine();
}
public static void ReadFile(Object fileName)
{
try
{
using (System.IO.StreamReader file1 = new System.IO.StreamReader(fileName.ToString()))
{
int x = 0;
string line = file1.ReadLine();
if (int.TryParse(line, out x))
{
lock (lockObject)
{
if (!Sum.HasValue)
{
Sum = x;
}
else
{
Sum = Sum + x;
}
}
}
else
{
Console.WriteLine("Invalid Integer in File: " + fileName.ToString() + "\r\nLine from File: " + line);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception Reading File: " + fileName.ToString() + "\r\nException: " + ex.Message);
}
}
}
答案 2 :(得分:1)
从@pescolino解释得非常好的答案开始,我们可以做出一些改进。首先,如果我们假设您的教师确实希望您使用实际的“线程”而不是任务 * ,我们仍然可以通过使用Interlocked
库而不是锁定来改进代码在手动对象上。这将为我们提供更好的性能,并且(更重要的是)更简单的代码。
private static void ReadIntFromFile(string filename)
{
string firstLine = System.IO.File.ReadLines(filename).First();
Interlocked.Add(ref result, int.Parse(firstLine));
}
现在,我不知道你是否已经介绍过LINQ了 - 我知道有时教师不喜欢学生使用他们尚未过去的工具 - 但如果你被允许,我们可以做主要方法更简单:
private static void Main()
{
var files = new[]{"File1.txt", "File2.txt", "File3.txt"};
var threads = files.Select(f => new Thread(() => ReadIntFromFile(f))).ToList();
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
Console.Write("Sum: {0}", result);
console.ReadLine();
}
现在,让我们来看看如果我们被允许使用任务,我们可以如何改变它:
private static void Main()
{
var files = new[]{"File1.txt", "File2.txt", "File3.txt"};
var tasks = files.Select(f => Task.Factory.StartNew(() => ReadIntFromFile(f)));
Task.WaitAll(tasks.ToArray());
Console.Write("Sum: {0}", result);
Console.ReadLine();
}
但是你知道,一旦我们使用LINQ和TPL,一种更“功能”的编程方法变得更有利。换句话说,不是让ReadIntFromFile方法添加到全局变量(ick!),而是让它返回它读取的值:
private static int ReadIntFromFile(string filename)
{
string firstLine = System.IO.File.ReadLines(filename).First();
return int.Parse(firstLine);
}
现在看看我们可以用main方法做些什么:
private static void Main()
{
var files = new[]{"File1.txt", "File2.txt", "File3.txt"};
int result = files.AsParallel().Sum(f => ReadIntFromFile(f));
Console.Write("Sum: {0}", result);
Console.ReadLine();
}
如果我们使用可用的所有工具,请查看简单的并行代码是多么简单?
*任务并不总是在不同的线程中运行 - 它们通常共享相同的线程。
答案 3 :(得分:0)
可能是某种形式:
public static void ReadFile1(ref int? x)
{
System.IO.StreamReader file1 = new System.IO.StreamReader( {FILEDESTINATION});
x = int.Parse(file1.ReadLine());
}
并使用
调用它int? res1 = null;
Thread t1 = new Thread(()=>ReadFile1(ref res1));
//...
t1.Start();
t1.Join();
System.Console.WriteLine("Sum: " + res1);
答案 4 :(得分:0)
线程不返回值。 ThreadStart
和ParameterizedThreadStart
个委托的回复类型为void
。
要使用线程执行此操作,您需要将结果存储在某处。如果它是共享变量,则在更新此值时需要lock
以避免冲突:
private object lockObj = new object();
private int result;
private static void Main()
{
result = 0;
Thread t1 = new Thread(() => ReadIntFromFile("File1.txt"));
Thread t2 = new Thread(() => ReadIntFromFile("File2.txt"));
Thread t3 = new Thread(() => ReadIntFromFile("File3.txt"));
t1.Start();
t2.Start();
t3.Start();
// don't forget to call Join to wait for the end of each thread
t1.Join();
t2.Join();
t3.Join();
Console.Write("Sum: {0}", result);
console.ReadLine();
}
private void ReadIntFromFile(string filename)
{
string firstLine = System.IO.File.ReadLines(filename).First();
lock (lockObj)
{
result += int.Parse(firstLine);
}
}
lock
关键字确保多个线程不能同时执行代码。如果您不使用lock
,结果可能是错误的。
由于您对每个文件使用不同的方法,当然可以使用不同的结果变量。那你就不需要锁了。但是如果你有100个文件怎么办?你可能不想写100个方法。
更简单的方法是使用TPL(自.NET 4起)。任务可以具有返回类型,并且更易于管理。我还改变了允许任意数量文件的方法:
private static void Main()
{
var sum = SumValuesFromFiles("File1.txt", "File2.txt", "File3.txt");
Console.Write("Sum: {0}", sum);
Console.ReadLine();
}
private static int SumValuesFromFiles(params string[] files)
{
Task<int>[] tasks = new Task<int>[files.Length];
for (int i = 0; i < files.Length; i++)
{
// use a local copy for the parameter because i might get changed before the method is called
string filename = files[i];
tasks[i] = Task.Factory.StartNew(() =>
{
string firstLine = System.IO.File.ReadLines(filename).First();
return int.Parse(firstLine);
});
}
Task.WaitAll(tasks);
return tasks.Sum(t => t.Result);
}
答案 5 :(得分:-1)
简单回答:你做不到。您必须编写收集结果的逻辑代码。即使用全局变量来保持总和。但是在更新总和时使用锁定。