Mejor técnica: lectura de datos en un subproceso

I've got a routine called GetEmployeeList that loads when my Windows Application starts.

This routine pulls in basic employee information from our Directorio Activo server and retains this in a list called m_adEmpList.

We have a few Windows accounts set up as Perfiles públicos that most of our employees on our manufacturing floor use. This m_adEmpList gives our employees the ability to log in to select features using those Perfiles públicos.

Una vez que todos los Directorio Activo data is loaded, I attempt to "auto logon" that employee based on the System.Environment.UserName if that person is logged in under their private profile. (employees love this, by the way)

If I do not thread GetEmployeeList, the Windows Form will appear unresponsive until the routine is complete.

El problema con GetEmployeeList is that we have had times when the Directorio Activo server was down, the network was down, or a particular computer was not able to connect over our network.

To get around these issues, I have included a ManualResetEvento m_mre con el THREADSEARCH_TIMELIMIT timeout so that the process does not go off forever. I cannot login someone using their Perfil privado con System.Environment.UserName until I have the list of employees.

I realize I am not showing ALL of the code, but hopefully it is not necessary.

public static ADUserList GetEmployeeList()
{
  if ((m_adEmpList == null) ||
      (((m_adEmpList.Count < 10) || !m_gotData) &&
       ((m_thread == null) || !m_thread.IsAlive))
     )
  {
    m_adEmpList = new ADUserList();
    m_thread = new Thread(new ThreadStart(fillThread));
    m_mre = new ManualResetEvent(false);
    m_thread.IsBackground = true;
    m_thread.Name = FILLTHREADNAME;
    try {
      m_thread.Start();
      m_gotData = m_mre.WaitOne(THREADSEARCH_TIMELIMIT * 1000);
    } catch (Exception err) {
      Global.LogError(_CODEFILE + "GetEmployeeList", err);
    } finally {
      if ((m_thread != null) && (m_thread.IsAlive)) {
        // m_thread.Abort();
        m_thread = null;
      }
    }
  }
  return m_adEmpList;
}

I would like to just put a basic bloquear usando algo como m_adEmpList, but I'm not sure if it is a good idea to lock something that I need to populate, and the actual data population is going to happen in another thread using the routine fillThread.

Si ManualResetEvento's EsperaUno timer fails to collect the data I need in the time allotted, there is probably a network issue, and m_mre does not have many records (if any). So, I would need to try to pull this information again the next time.

If anyone understands what I'm trying to explain, I'd like to see a better way of doing this.

It just seems too forced, right now. I keep thinking there is a better way to do it.

preguntado el 09 de septiembre de 13 a las 21:09

1 Respuestas

I think you're going about the multithreading part the wrong way. I can't really explain it, but threads should cooperate and not compete for resources, but that's exactly what's bothering you here a bit. Another problem is that your timeout is too long (so that it annoys users) and at the same time too short (if the AD server is a bit slow, but still there and serving). Your goal should be to let the thread run in the background and when it is finished, it updates the list. In the meantime, you present some fallbacks to the user and the notification that the user list is still being populated.

A few more notes on your code above:

  • You have a variable m_thread that is only used locally. Further, your code contains a redundant check whether that variable is null.
  • If you create a user list with defaults/fallbacks first and then update it through a function (make sure you are checking the InvokeRequired flag of the displaying control!) you won't need a lock. This means that the thread does not access the list stored as member but a separate list it has exclusive access to (not a member variable). The update function then replaces (!) this list, so now it is for exclusive use by the UI.
  • Lastly, if the AD server is really not there, try to forward the error from the background thread to the UI in some way, so that the user knows what's broken.
  • If you want, you can add an event to signal the thread to stop, but in most cases that won't even be necessary.

Respondido el 09 de Septiembre de 13 a las 21:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.