0

I'm new to Multithreading and began to do some research and experiments and recently wrote a Multithreading web form in C#, that dynamically, creates threads depending the number of cores installed on the server. Each thread shares and array and has two parameters. The array is previously filled with data and the parameters contains the beginning position to process in the array and the number of elements to process.

My code is this :

Hilos.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Hilos.aspx.cs" Inherits="Hilos" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Label ID="lbl" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>

Hilos.aspx.cs

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;

public partial class Hilos : System.Web.UI.Page
{
  static List<int> var = new List<int>();
  static List<object> hilo = new List<object>();

  string[] abc = { "abc", "def", "ghi", "jkl", "mnñ", "opq", "rst", "uvw", "xyz" };
  List<string> lstStr = new List<string>();

  protected void Page_Load(object sender, EventArgs e)
  {
    if (!Page.IsPostBack)
    {            
        int elementosPorHilo = (int)Math.Truncate((double)(abc.Length / Environment.ProcessorCount));
        int elementosUltimoHilo;
        int elementosProcesar;
        int posInicioProcesar = 0;
        List<Thread> thr = new List<Thread>();

        if (elementosPorHilo * Environment.ProcessorCount != abc.Length)
        {
            elementosUltimoHilo = elementosPorHilo + abc.Length - (elementosPorHilo * Environment.ProcessorCount);
        }
        else
        {
            elementosUltimoHilo = elementosPorHilo;
        }

        elementosProcesar = elementosPorHilo;

        //This for creates the threads and should create one core per avaiable thread on the processor(s)
        for (int i = 1; i < Environment.ProcessorCount + 1; i++)
        {
            if (i == Environment.ProcessorCount)
            {
                elementosProcesar = elementosUltimoHilo;
            }
            Thread tdr = new Thread(() => rnd(elementosProcesar, posInicioProcesar));
            tdr.Start();
            thr.Add(tdr);
            posInicioProcesar += elementosProcesar;
        }
        foreach (Thread tdr in thr)
        {
            tdr.Join();
        }
        lbl.Text = string.Concat(lstStr.ToArray());
      }
  }
  /// <summary>
  /// Code executed by the Thread
  /// </summary>
  /// <param name="iter">How many times it will iterate</param>
  /// <param name="posinicio">The start position inside the Array</param>
  private void rnd(int iter, int posinicio)
  {

    string str = "";

    for (int iterador = 0; iterador < iter; iterador ++)
    {
        str += abc[iterador + posinicio];
    }

    lstStr.Add(str);    
   }
  }

I'm running this on a four cores Core i3 pc (4 threads because HyperThreading) Windows 7 x86. The problem I'm having is that the code is creating 5 threads and the last thread obviously is created with parameters outside the limits of the array.

The last one correct thread is created with iter = 3 and posinicio = 6 and after that another thread is created with iter = 3 and posinicio = 9 and when it executes, sends and error indicating out of index exception.

I know it can be controlled in the for that creates de threads but i would like to understand why it is this happening.

Thanks you and sorry for the long post.

Pipe2290
  • 168
  • 2
  • 10
  • Appearently the error i'm getting is because the values of elementosProcesar and posInicioProcesar changes before the thread is created. Any recomendation to assign values to a thread, start the thread and change the values without getting this error? – Pipe2290 Mar 18 '15 at 19:16
  • It would be easier if the variable names were english... Have you tried making the for loop start at i = 0 and run to i < Environment.ProcessorCount? Is this just a test project try out threads? Creating new Threads in this fashion is only recommended for long running background operations. You might want to take a look at the newer Task library (System.Threading.Tasks), which is much easier to work with. – sondergard Mar 18 '15 at 19:19
  • 1
    This is a very classic problem, I'll find a duplicate. Your lambda is 'capturing' or 'closing over' variables from the outer scope. – H H Mar 18 '15 at 19:19
  • You are right. The solution was to create the variables that i need to assign to the thread and copy the values before create the thread. The final code will look like: int param1; int param2; param1 = elementosProcesar; param2 = posInicioProcesar; Thread tdr = new Thread(() => rnd(param1 , param2)); tdr.Start(); thr.Add(tdr); Thanks for the help guys! ^-^ – Pipe2290 Mar 18 '15 at 19:43

0 Answers0