Digital I/O

cancel
Showing results for 
Search instead for 
Did you mean: 

PCI-6527 initialization issue (C++)

Hi!

I am experiencing an interesting issue when programming with NIDAQmx in Visual C++ 2003. Application I am writing has multiple threads. All of them open it's own initialization file. Everything works OK without DAQmx. However, when I use any DAQmx funciton (e.g. DAQmxResetDevice), other threads can't open their initialization files. After much lost hours, I then put a delay infront of first DAQmx function call (Sleep (10)) and now everything works without any problems. Thus, I would imagine that there is some DLL library that doesn't load fast enough.
I would really like to get rid of delay in my application, thus I thought I could load DLLs explicitly. What I would like to know is what DLL files must I load and what are your thoughts on this.

Best regards,
Vladimir Kocjancic

Message Edited by kovalenkov on 02-25-2007 12:19 PM

0 Kudos
Message 1 of 28
(5,827 Views)
Hi Vladimir,

Here is a forum which discusses DAQ multithreading. What version of the DAQ driver are you using, along with what hardware? Does your initialization file have anything to do with DAQ? Is there any specific reason why you are using the DAQmxResetDevice? This function will take a finite amount of time, thus we must use a delay. Does this problem happen when using other functions or just the DAQmxResetDevice? Lastly, are you closing all of your references in your threads?
David L.
Systems Engineering
National Instruments
0 Kudos
Message 2 of 28
(5,753 Views)
Hi David!

First to answer your questions.
1) I believe that I am using NI-DAQmx 8.2 driver.
2) The initialization file has nothing to do with DAQ and that is why I find it odd. The code literally crashes on call of CreateFile function.
3) The reason I am using DAQmxResetDevice is that at the start of application all outputs must be reset no matter what. Anyway, it doesn't help if I use any other DAQmx function there as well. All return the same result and that is crash of the application.
4) The application itself works 24/7 with DAQ Traditional drivers at the moment without any issues. Also, only one thread handles DAQmx requests, while all others (3) have nothing to do with DAQmx or it's functions.

Regarding multithreading link you sent, it has been useful to help understand how multithreading works with DAQmx however I fail to see how this has anything to do with the problem I am experiencing.
Seeing that a little thing like putting Sleep (10) prior first DAQmx statement, I would assume it has something to do with libraries not loading up in time. Or it seems so anyway.


Message Edited by kovalenkov on 02-27-2007 07:58 AM

0 Kudos
Message 3 of 28
(5,750 Views)
Hello Vladimir,
 
In order to get a more complete understanding of the encountered issue, what are the exact symptoms? Namely, your first posting states that "threads can't open their initialization files" when you use any DAQmx function, while your second posting mentions a "crash". It would help to get as specific as possible.
 
Also, can you share any more details about the application to specifically add more context on how your code executes? It would be best if you could provide some source code. Namely, when you say "when I use any DAQmx function", do you mean immediately after or before the code that attempts to open the initialization file? Is this code executing in the context of a dllMain by any chance?
 
Answers to these question might help us to get to the bottom of your issue.
 
 

Regards,

Regrads,
Sead Suskic
National Instruments
0 Kudos
Message 4 of 28
(5,746 Views)
Hello Sead!

I am terribly sorry for confusion. What I meant to say is that calling first function of DAQmx causes the other threads to fail while opening their initialization files and thus, the application "crahses" or stops executing and reports an error, which in my case is a feature (reporting error, not failing to read initialization file).

Regarding source code. The application is very object oriented and modular. Thus, pasting a code here would be useless without some long and exhausting description. I will try to explain the sequence in which things occur.

1) Application starts and creates 4 other threads in suspended mode.
2) Application then starts all threads one by one. Thread that is the only one which uses DAQmx is started first.
3) Initilaization of DIO starts. First function to call is DAQmxResetDevice.
4) Meanwhile, also initialization of other threads is triggered by main thread.
5) When one of the other threads tries to open a file using CFile class, it fails. Thus, the application ends with an error.

N.B. 1: It does not matter if first function called is DAQmxResetDevice. It can be any other valid DAQmx function call, like DAQmxCreateTask.
N.B. 2: If a delay of 10 ms is put in front of first DAQmx function call, the application works without any issues. All threads open ther initialization files and do their work.
N.B. 3: The application worked without any issues while using DAQ Traditional drivers and it hasn't been changed except changing form Traditional to mx drivers.

Best regards,
Vladimir Kocjancic
0 Kudos
Message 5 of 28
(5,730 Views)
Vladimir,

Are you doing managed or unmanaged code? Please make sure you are not trying to communicate with any user interface (UI) objects throughout threads. Does your code work OK without the wait timer if you do not spawn any other threads? If so, please have your main thread spawn one thread which either does nothing or does a simple print statement as acknowledgement of this spawn.

Putting more clarification on how your initialization files are working, do you spawn a thread and then open an initialization file inside that thread using CreateFile Function? It would be very helpful if you could post a small piece of code which does simple daqmx tasks, along with spawning a simple thread. This will help us see how you are coding and paint a better overall picture of the situation.
David L.
Systems Engineering
National Instruments
0 Kudos
Message 6 of 28
(5,710 Views)
David,

The application is unmanaged and document based MFC application with static linking. Main thread handles and processes all UI requests. Other theads are used either for data aquisition or data handling.
After I changed the code in a way that only the thread with DAQmx started, everything worked fine. The same was when I spawned another thread with messagebox output.

Regarding initialization in threads is concerned it is exactly as you have written and as I have mentioned in one of the early posts. First, the thread is started and then in the InitInstance method, which occurs when you call ResumeThread in main thread, the initialization file is read at some point.

Regarding code, I must say that I have not experienced this issue when testing DAQmx driver in console or test MFC application. It is reading of file that bothers it somewhat. BTW, I did a mistake writing that I use CreateFile. I am using CFile object with assigned special class to handle input and output of data. Since everything works fine in console application, it would be useless to post code here. However, I posted part of code that spawns threads, opens the file and does some DAQmx function calling.

In the main thread:
'...
if (bInitOK) {
        m_pDioNit = (CDioNit*) AfxBeginThread(RUNTIME_CLASS(CDioNit), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
        if(m_pDioNit == NULL)
        {
            bInitOK = FALSE;
            logPodatki[1].Format(_T("%d"),GetLastError());
            if (!ReportEvent(m_hLog,EVENTLOG_ERROR_TYPE,0,E0007,NULL,VELIKOST_BUFFERJA_LOG,0,(LPCTSTR*)logPodatki,NULL))
                AfxMessageBox(IDS_E0001,MB_ICONERROR);
        }
    }

    if (bInitOK) {
        m_pTermNit = (CTermNit*) AfxBeginThread(RUNTIME_CLASS(CTermNit), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
        if(m_pTermNit == NULL)
        {
            bInitOK = FALSE;
            delete (m_pDioNit);
            m_pDioNit = NULL;
            m_bDioZiv = FALSE;
            logPodatki[1].Format(_T("%d"),GetLastError());
            if (!ReportEvent(m_hLog,EVENTLOG_ERROR_TYPE,0,E0008,NULL,VELIKOST_BUFFERJA_LOG,0,(LPCTSTR*)logPodatki,NULL))
                AfxMessageBox(IDS_E0001,MB_ICONERROR);
        }
    }

    if (bInitOK) {
        m_pTemmNit = (CTemmNit*) AfxBeginThread(RUNTIME_CLASS(CTemmNit), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
        if(m_pTemmNit == NULL)
        {
            bInitOK = FALSE;
            delete (m_pDioNit);
            m_pDioNit = NULL;
            m_bDioZiv = FALSE;
            delete (m_pTermNit);
            m_pTermNit = NULL;
            m_bTermZiv = FALSE;
            logPodatki[1].Format(_T("%d"),GetLastError());
            if (!ReportEvent(m_hLog,EVENTLOG_ERROR_TYPE,0,E0009,NULL,VELIKOST_BUFFERJA_LOG,0,(LPCTSTR*)logPodatki,NULL))
                AfxMessageBox(IDS_E0001,MB_ICONERROR);
        }
    }
...
if((m_pDioNit!=NULL) && bInitOK)
    {
        m_pDioNit->m_pMainWnd = m_pMainWnd;
        m_pDioNit->m_pTermNit = m_pTermNit;
        m_pDioNit->m_hHeapNapake = m_hHeapNapake;
        m_pDioNit->m_bAutoDelete = FALSE;
        m_pDioNit->m_hLog = m_hLog;
        m_pDioNit->ResumeThread();
    }

    if((m_pTermNit!=NULL) && bInitOK)
    {
        m_pTermNit->m_pMainWnd = m_pMainWnd;
        m_pTermNit->m_pDioNit = m_pDioNit;
        m_pTermNit->m_hHeapNapake = m_hHeapNapake;
        m_pTermNit->m_hHeapTemperature = m_hHeapTemperature;
        m_pTermNit->m_bAutoDelete = FALSE;
        m_pTermNit->m_hLog = m_hLog;
        m_pTermNit->ResumeThread();
    }

    if((m_pTemmNit!=NULL)&& bInitOK)
    {
        m_pTemmNit->m_pMainWnd = m_pMainWnd;
        m_pTemmNit->m_pTermNit = m_pTermNit;
        m_pTemmNit->m_hHeapNapake = m_hHeapNapake;
        m_pTemmNit->m_hHeapTemperature = m_hHeapTemperature;   
        m_pTemmNit->m_bAutoDelete = FALSE;
        m_pTemmNit->m_hLog = m_hLog;
        m_pTemmNit->ResumeThread();
    }
'

Opening initialization file. Same for every thread (ecxcept class that is). Part where other threads fail is bolded.
'...
if(bInitOK)
    {
        try
        {
            CFile initFile (_T(".\\INIT\\DioInit.dat"), CFile::modeRead);
            CArchive ar (&initFile, CArchive::load);
            ar >> pDioInit;
            ar.Close ();
            initFile.Close ();
            m_fPretokVode = pDioInit->m_fPretokVode;
            m_nCasTimerZamikIzklopaP1 = pDioInit->m_nCasTimerZamikIzklopaPX;
        }
        catch (CFileException* fe)
        {
            bInitOK = FALSE;
            PosljiNapakoInPisiLog (1001, fe->m_cause, IDS_E1001, E1001, FALSE, WM_DIO_NAPAKA, 0, EVENTLOG_ERROR_TYPE);
            ATLTRACE2("DIO: Napaka pri dostopu do INIT datoteke!\n");
            fe->Delete ();
        }
    }
    ...
'

Initialization of DIO PCI card:
'...
int CDioKartica::Init ()
{
    _stprintf (m_pszVhodniKanali, _T("%s/port0/line0:7, %s/port1/line0:7, %s/port2/line0:7"), m_pszImeNaprave, m_pszImeNaprave, m_pszImeNaprave);
   
    Sleep (10);

    m_nStatus = DAQmxResetDevice (CW2A (m_pszImeNaprave));
    if (m_nStatus == DIO_OK)
        m_nStatus = DAQmxCreateTask ("Vhodi", &m_hTaskVhodi);

    if (m_nStatus == DIO_OK)
        m_nStatus = DAQmxCreateDIChan (m_hTaskVhodi, CW2A(m_pszVhodniKanali), "", DAQmx_Val_ChanPerLine);

    if (m_nStatus == DIO_OK)
        m_nStatus = DAQmxSetDIDigFltrEnable (m_hTaskVhodi, CW2A(m_pszVhodniKanali), 0);

    if (m_nStatus == DIO_OK)
        m_nStatus = DAQmxSetDIDigFltrMinPulseWidth (m_hTaskVhodi, CW2A(m_pszVhodniKanali), 0.020);

    if (m_nStatus == DIO_OK)
        m_nStatus = DAQmxSetDIDigFltrEnable (m_hTaskVhodi, CW2A(m_pszVhodniKanali), 1);

    if (m_nStatus == DIO_OK)
        m_nStatus = DAQmxStartTask (m_hTaskVhodi);

    return m_nStatus;
}

...'

Message Edited by kovalenkov on 03-02-2007 05:00 PM

0 Kudos
Message 7 of 28
(5,703 Views)
Hi Vladimir,

Can you post the stack trace before your constructor to CFile fails?  If possible, can the stack trace also include symbols for the Windows components.

Jeff

Message Edited by jcarbonell on 03-05-2007 08:40 AM

0 Kudos
Message 8 of 28
(5,686 Views)
Hi Jeff,

As far as I know, there is no such thign as in-built stack tracer in C++ unmanaged code. Do you perhaps have an application you can advise me to use?

Best regards,
Vladimir
0 Kudos
Message 9 of 28
(5,667 Views)


@kovalenkov wrote:
Hi Jeff,

As far as I know, there is no such thign as in-built stack tracer in C++ unmanaged code. Do you perhaps have an application you can advise me to use?

Best regards,
Vladimir


Hi Vladimir---

Sure, the Visual Studio Debugger has a way to display the stack trace. Stick a breakpoint on the offending line and get your code to break.   (With Visual Studio 2005) Go to the Debug menu::Windows::Call Stack.  The call stack window should pop up or be docked someplace.  Give the window focus, select all, copy, and paste the text in a reply message.  Visual Studio 2003 should be similar.

The stack trace will look something like

>    test1.exe!ConsumerThread(void * parameter=0x00000000)  Line 220    C++
     kernel32.dll!_BaseThreadStart@8()  + 0x37 bytes   

To get the best stack trace results, you may need to  Visual Studio 2003 or Visual Studio 2005 to use the Microsoft symbol server.

Hope this helps,

Jeff
0 Kudos
Message 10 of 28
(5,662 Views)