我有一个函数,它将变量作为参数并返回计算结果。该函数分为其他函数,每个函数都进行自己的计算。我需要该函数来运行多线程。
我的代码:
for (int i = 0; i < pic.Width; i++)
{
for (int k = 0; k < pic.Height; k++)
{
var localK = k;
var localI = i;
Image bestPic;
new Thread(() =>
{
bestPic = new Bitmap(getBestPic(argb));//THIS IS WHERE THE WRONG VALUES ARE ASSIGNED BECAUSE OF CROSS THREADING
lock (thisLock)
{
g.DrawImage(bestPic, localI * bestPic.Width, localK * bestPic.Height, bestPic.Width, bestPic.Height);
}
}).Start();
}
}
我需要的只是函数getBestPic来运行多线程。但是如何运行getBestPic函数多线程并将返回的结果赋值给bestPic变量原子?
如果需要,我的整个节目:这是一个蒙太奇计划。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Drawing;
namespace test
{
public partial class Form1 : Form
{
private static readonly Object thisLock = new Object();
private Graphics g;
private Bitmap returnImg;
private Bitmap pic;
private int done = 0;
private int pictureWidthAndLength = 200;
private string inputPicName = "test";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime dtStart = DateTime.Now;
pic = new Bitmap(inputPicName + ".jpg");
//MessageBox.Show(pic.GetPixel(1,1).ToArgb().ToString());
//MessageBox.Show(pic.Width.ToString() + " x " + pic.Height.ToString());
returnImg = new Bitmap(pic.Width * pictureWidthAndLength, pic.Height * pictureWidthAndLength);
using (g = Graphics.FromImage(returnImg))
{
Color clr;
int[] argb = new int[4];
for (int i = 0; i < pic.Width; i++)
{
for (int k = 0; k < pic.Height; k++)
{
clr = pic.GetPixel(i, k);
argb[0] = clr.A;
argb[1] = clr.R;
argb[2] = clr.G;
argb[3] = clr.B;
var localK = k;
var localI = i;
Image bestPic;
if (cbxthreading.Checked)
{
new Thread(() =>
{
bestPic = new Bitmap(getBestPic(argb));
lock (thisLock)
{
g.DrawImage(bestPic, localI * bestPic.Width, localK * bestPic.Height, bestPic.Width, bestPic.Height);
done++;
}
}).Start();
}
else
{
//Single threaded
bestPic = new Bitmap(getBestPic(argb));
g.DrawImage(bestPic, localI * pictureWidthAndLength, localK * pictureWidthAndLength, pictureWidthAndLength, pictureWidthAndLength);
}
//MessageBox.Show(getBestPic(argb));
}
}
if (cbxthreading.Checked)
{
int loopNum = pic.Width * pic.Height;
while (done < loopNum) { }
}
}
DateTime dtEnd = DateTime.Now;
MessageBox.Show((dtEnd - dtStart).ToString());
}
//Get picture that is best suited to replace pixel
private string getBestPic(int[] argb)
{
int numOfpics = 5;
int[] currentBest = new int[2];
currentBest[0] = 255;
currentBest[1] = 150;
for (int i = 0; i < numOfpics; i++)
{
int compare = compareARGB(getAverageRGB(new Bitmap((i + 1).ToString()+".jpg")), argb);
if (compare < currentBest[0])
{
currentBest[0] = compare;
currentBest[1] = i + 1;
}
}
return currentBest[1].ToString() + ".jpg";
}
// smaller the value, closer the camparison
private int compareARGB(int[] one, int[] two)
{
int [] tmp = new int[4];
tmp[0] = Convert.ToInt32(Math.Abs(one[0] - two[0]));
tmp[1] = Convert.ToInt32(Math.Abs(one[1] - two[1]));
tmp[2] = Convert.ToInt32(Math.Abs(one[2] - two[2]));
tmp[3] = Convert.ToInt32(Math.Abs(one[3] - two[3]));
return (tmp[0] + tmp[1] + tmp[2] + tmp[3]);
}
//return int arry with size 4 containing the argb values
private int[] getAverageRGB(Bitmap img)
{
Color clr;
int aplha = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < img.Width; i++)
{
for (int k = 0; k < img.Height; k++)
{
clr = img.GetPixel(i, k);
aplha += clr.A;
red += clr.R;
green += clr.G;
blue += clr.B;
}
}
aplha = aplha / (img.Width * img.Height);
red = red / (img.Width * img.Height);
green = green / (img.Width * img.Height);
blue = blue / (img.Width * img.Height);
int[] re = new int[] {aplha,red,green,blue};
return re;
}
private void button2_Click(object sender, EventArgs e)
{
returnImg.Save(inputPicName+".bmp");
MessageBox.Show("Done!");
}
}
}
单线程功能有效,但需要很长时间。多线程功能也在单线程的三分之一时间内完成,但结果不正确。
答案 0 :(得分:1)
getBestPic()
方法运行多线程。但问题是argb
参数。您初始化它们然后在for循环中覆盖它的值。argb
是引用类型,因此只有引用传递给getBestPic()
,因此它的引用值在{{{}}处理时会被更改1}}。
我会尝试通过Value传递它或将getBestPic()
行移动到第二个for循环的内部,所以每次初始化新变量。有关传递引用类型参数here的更多信息。
答案 1 :(得分:0)
只需在Value
方法中创建argb
getBestPic()
的副本,然后使用它而不是使用原始版本
private string getBestPic(int[] argb)
{
int[] argbCopy = argb.ToArray();
int numOfpics = 5;
int[] currentBest = new int[2];
currentBest[0] = 255;
currentBest[1] = 150;
for (int i = 0; i < numOfpics; i++)
{
int compare = compareARGB(getAverageRGB(new Bitmap((i + 1).ToString()+".jpg")), argbCopy);
if (compare < currentBest[0])
{
currentBest[0] = compare;
currentBest[1] = i + 1;
}
}
return currentBest[1].ToString() + ".jpg";
}