multithreading - C# threading incrementing an integer higher than expected -


firstly want apologize program being half done, want try , fix problem before continue program.

the following in entire solution far:

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 {     public form1()     {         initializecomponent();     }      private void button1_click(object sender, eventargs e)     {         datetime dtstart = datetime.now;          bitmap pic = new bitmap("test.jpg");          bitmap returnimg = new bitmap(pic.width, pic.height);         graphics g = graphics.fromimage(pic);          color clr;         int[] argb = new int[4];          (int = 0; < pic.width; i++) // pic.width = 50         {             (int k = 0; k < pic.height; k++) // pic.height = 50             {                 clr = pic.getpixel(i, k);                 argb[0] = clr.a;                 argb[1] = clr.r;                 argb[2] = clr.g;                 argb[3] = clr.b;                   new thread(() =>                 {                     if (k < 50)                     {                         //here problem, integer k still gets value 50 assigned it.                         g.drawimage(new bitmap(getbestpic(argb)), new point(i, k));                     }                 }).start();              }         }         returnimg = new bitmap(pic.width, pic.height, g);         returnimg.save("createdimage.jpg");     }      //get picture best suited replace pixel     private string getbestpic(int[] argb)     {         int numofpics = 5;         int[] currentbest = new int[2];         currentbest[0] = 255;         currentbest[1] = 150;          (int = 0; < numofpics; i++)         {             int compare = compareargb(getaveragergb(new bitmap((i + 1).tostring()+".jpg")), argb);             if (compare < currentbest[0])             {                 currentbest[0] = compare;                 currentbest[1] = + 1;             }         }         return currentbest[1].tostring() + ".jpg";     }      // smaller value, closer 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 size 4 contaning argb values     private int[] getaveragergb(bitmap img)     {         color clr;         int aplha = 0;         int red = 0;         int green = 0;         int blue = 0;         (int = 0; < img.width; i++)         {             (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;     } } } 

this montage program creating. comparing each pixel rgb of main picture average rgb of list of thumbnails. thumbnail average rgb closes pixel rgb used replace pixel.

i know there going lot of criticism of program. know resolution of resulting picture going huge ens.

the issue want why integer k in button1_click function increasing value 50, when there check less 50 in thread , loop k should not go 50. issue not occur when take threading out , happens randomly. value of integer varies when program breaks (because k gets assigned value 50). why cannot use break point or step through program. because happen randomly, when there lot of threads created.

thanks on this.

the issue results fact c# closures capture variable itself, not value. combined scoping of for-loop variable prior c# 5.0 mean value of k seen code running on separate thread change loop on main thread iterates through values, , in case importantly, can change between if (k < 50) check , subsequent use of k. msdn describes changes in c# 5.0 here.

if catch @ right moment, value of k can increment 50 51 result of for-loop on final iteration after if (k < 50) check before if-statement body.

as result of same issue, you'll find values of k skipped, , processed multiple times different threads.

to resolve need assign k local variable , capture instead. since variable localk local iteration of loop, captured value not change within thread:

            ...             var localk = k;             new thread(() =>             {                 if (localk < 50)                 {                     g.drawimage(new bitmap(getbestpic(argb)), new point(i, localk));                 }             }).start();             ... 

it's worth adding it's practically guaranteed running in threaded manner drastically reduce performance overhead of creating , switching between 2500 threads far outweigh benefit might gained parallel processing.


Comments