PDA

View Full Version : QThread, bad file descriptor



saman_artorious
22nd April 2013, 11:26
I created an instance of RS class inside MainWindow. when fd is opened, it gives the value of 19 inside debugger. But, when I access it from inside of the Thread, it always gives value 0.

this is my main file: it initializes a thread that regularly generates packets inside queue as producer, and consumer on the other end, writes them to serial.

serial port is opened in Mainwindow constructor:

rs_plc.rs_plcOpenPort((char *)"/dev/ttyS0"); /*/dev/ttyS3*/



ThreadSafeQueue<QByteArray> UpdateJackQueue;
PlcUpdateThread *plcUpdateProd = new PlcUpdateThread(UpdateJackQueue, 1);
plcUpdateProd->start();

PlcUpdateThread *plcUpdateCons = new PlcUpdateThread(UpdateJackQueue, 0);
plcUpdateCons->start();


here is the Thread:


#ifndef PLCUPDATETHREAD_H
#define PLCUPDATETHREAD_H

#include <QByteArray>
#include <QThread>
#include "threadsafequeue.h"
#include "safilanLib.h"
#include "rs485.h"

#include <QDebug>

class PlcUpdateThread : public QThread
{
Q_OBJECT
public:
PlcUpdateThread(ThreadSafeQueue<QByteArray> &q, bool isProducer) : _queue(q), _prod(isProducer) {
if(_prod)
qDebug() << "I am a producer";
else
qDebug() << "I am a consumer";
}

void run() {
if(_prod)
while(1) produce();
else
while(1) consume();
}


void produce() {

const char str[]={UPDATE_xx};

QByteArray built((char*)str, 3) ;

_queue.enqueue(built);

// qDebug() << _queue.count();

msleep(100);
//sleep(qrand()%5);
}

void consume() {
qDebug() << "cosume";
QByteArray v = _queue.dequeue();

qDebug() << v.toHex();
rs_plc.writeToSerialPort(v);

qDebug() << _queue.count();
msleep(300);
// sleep(qrand()%5);
}


public slots:

private:
ThreadSafeQueue<QByteArray> &_queue;
bool _prod;
};

#endif // PLCUPDATETHREAD_H



here is the write to serial function that the above thread calls:

and here is the RS instance created statically write after the RS class:


void rs_flushPort ();
bool rs_plcConfigPort();
bool rs_azmthConfigPort();

};

static RS rs_plc;

wysota
22nd April 2013, 12:00
Please provide a minimal compilable example reproducing the problem.

saman_artorious
22nd April 2013, 12:09
Please provide a minimal compilable example reproducing the problem.

can't be more minimized than above now. I omitted serial write, forget about it.
When fd is set in RS class instance, when I access serial class member from thread, fd is 0. However, If I open and close serial port inside thread everytime I write then it writes successfully! should I keep that way?

this way it works fine:


void consume() {
qDebug() << "cosume";
QByteArray v = _queue.dequeue();

qDebug() << v.toHex();
rs_plc.rs_plcOpenPort((char *)"/dev/ttyS0");
rs_plc.writeToSerialPort(v);

qDebug() << _queue.count();
msleep(300);
// sleep(qrand()%5);
}


moreover, the other problem is with reading. inside another thread, I read serial by producer and update ui by consumer, but producer never reads from serial, even when I send a packet via DB9 ,it does not catch it. here is the reading and updating ui thread:


void produce() {

qDebug() << "produce";

QByteArray rd15Bytes;

if(rs_plc.rs_plcRead(&rd15Bytes))
{
if(!rd15Bytes.isEmpty())
{
// qDebug() << "Enqueue";
_queue.enqueue(rd15Bytes);
}
}

msleep(100);
}

void consume() {
qDebug() << "cosume";

QByteArray v = _queue.dequeue();

rs_plc.updateUI(v);

msleep(200);
}


you may not worry about read and write functions to serial, as they are properly checked and work fine without using threads.

wysota
22nd April 2013, 13:40
can't be more minimized than above now.
But it can be more compilable than now.

saman_artorious
22nd April 2013, 14:10
let me think how to tell you what I really want to do.

saman_artorious
22nd April 2013, 20:33
thanks for the producer consumer problem you referenced. i tried it. I use two instances of this class, in the first, producer writes packets to queue, consumer dequeues and writes them to serial. (So, two threads). in the next two threads, producer reads from serial constantly and enqueues buffer, the consumer then dequeues and updates UI.
I have the following problems:

1. in this class queue is defined privately inside threadsafequeue, this causes some problems, other objects cannot enqueue inside the queue if it is private! I have defined the threads in main.cpp. but how can other object tell it that they want these packets enQd into queue. so that the consumer can write them to serial? on the other hand if I define the queue not inside of the class and instead in a global header, I receive multiple definition of variable error.

2.Let's consider four threads, the RS class that communicates with serial and other objects that enqueue packets to queue to be written to serial. The write to serial in producer works fine. but the consumer can never read from serial, always returns length 0 or rarely length that is less than expected. Moreover, in this class I cannot pass packets to thread, otherwise, other object coudav used thread instance to enquque packets into its Q.

3. I used emit in a single thread, it works fine, but in the producer consumer class emit are not active. when I receive the packet from serial inside of RS class, I emit it to UI. but it doesn't work!

I do not know how to correct the structure of my program. please help me. I added the code above to clarify what is happening in my code.
please ask me for further info, i am very curious to solve the structure of my program with threads.

thanks for the producer consumer problem you referenced. i tried it. I use two instances of this class, in the first, producer writes packets to queue, consumer dequeues and writes them to serial. (So, two threads). in the next two threads, producer reads from serial constantly and enqueues buffer, the consumer then dequeues and updates UI.
I have the following problems:

1. in this class queue is defined privately inside threadsafequeue, this causes some problems, other objects cannot enqueue inside the queue if it is private! I have defined the threads in main.cpp. but how can other object tell it that they want these packets enQd into queue. so that the consumer can write them to serial? on the other hand if I define the queue not inside of the class and instead in a global header, I receive multiple definition of variable error.

2.Let's consider four threads, the RS class that communicates with serial and other objects that enqueue packets to queue to be written to serial. The write to serial in producer works fine. but the consumer can never read from serial, always returns length 0 or rarely length that is less than expected. Moreover, in this class I cannot pass packets to thread, otherwise, other object coudav used thread instance to enquque packets into its Q.

3. I used emit in a single thread, it works fine, but in the producer consumer class emit are not active. when I receive the packet from serial inside of RS class, I emit it to UI. but it doesn't work!

I do not know how to correct the structure of my program. please help me. I added the code above to clarify what is happening in my code.
please ask me for further info, i am very curious to solve the structure of my program with threads.

wysota
22nd April 2013, 20:45
First of all I don't understand why you are using threads at all here if they are causing you problems. Implement your program in a single thread instead.

saman_artorious
23rd April 2013, 07:23
I did but it slows down the UI. because when timers trigger, they write and read from serial. So, meanwhile entering input in the UI will not be fast. The write n read to the serial is in the way that when I write, I delay() a bit followed by the read. Then I emit the read packet to UI. This is why decided to use Thread to handle write n read to serial in another thread so that UI does not have to wait for serial write n reads.
What should I do ?

wysota
23rd April 2013, 07:29
I did but it slows down the UI.
If it does then apparently you have not done it correctly.

saman_artorious
23rd April 2013, 08:29
and about the bad file descriptor. say, I have a serial class:


class RS
{
}
static RS var

I open this port in mainwindow, but when I access its member function from inside of a thread using the static variable


::run()
{
staticvariable.sendToserial(param);
msleep(300);
}

it gives bad file descriptor. it seems that the variable fd defined inside serial class gets lost!
I also replaced opening port from mainwindow to serial class constructor, this way when program runs, it opens port many times!

any ideas?

kuzulis
23rd April 2013, 09:16
The best idea is to use ready classes wrappers for work with serial ports in Qt. For example QtSerialPort (http://qt-project.org/wiki/QtSerialPort) (preferred) or QextSerialPort.
It much quicker and more conveniently, than you will fool about with threads, etc., IMHO.

wysota
23rd April 2013, 09:26
and about the bad file descriptor. say, I have a serial class:


class RS
{
}
static RS var

I open this port in mainwindow, but when I access its member function from inside of a thread using the static variable


::run()
{
staticvariable.sendToserial(param);
msleep(300);
}

it gives bad file descriptor. it seems that the variable fd defined inside serial class gets lost!
I also replaced opening port from mainwindow to serial class constructor, this way when program runs, it opens port many times!

any ideas?

I have no idea what your code as doing and since you're not willing to show your code but instead all you do is provide random snippets that do not demonstrate the problem, there is nothing I (and possibly all the other participants) can do for you.

saman_artorious
23rd April 2013, 13:47
Ok, Consider this thread, it acts like a timer, send some packet to serial:


void PlCThead::run()
{
while(1)
{
const char str[]={UPDATE_PACKET};

emit requestForWriteAndReceive((char* )str, 3);

msleep(100);
}
}


emit works fine, it goes inside the slot, there, it writes only 78 or char x to serial instead of a packet of 3 bytes.




bool RS::rs_serialWrite(char* buff, size_t length)
{
int variables....;

QByteArray built((char*)buff, length);
qDebug() << built.toHex(); //this is correct, a packet of size 3

len = write(fd, buff, length);

qDebug() << len; //this returns 3! but it only write x to serial

qDebug() << strerror(errno);

return true;
}


strerror returns back this warning:

Resource temporarily unavailable

any ideas? this code works fine with timers, it has been checked and tested accurately, but now i need to add this thread instead of the timer. Thanks (;))

wysota
23rd April 2013, 15:39
As I already said about a week ago, your code in run() is invalid. You are emitting a pointer to a local variable which you'll likely overwrite with other data before anyone has a chance to use the pointer. Emit a byte array instead or use some other data structure to share data between threads. Or drop threads, you really have no need for them.

saman_artorious
23rd April 2013, 19:32
i cannot attach files here, I will attach it in a new post.

saman_artorious
23rd April 2013, 19:34
I cannot simply omit char* and use QByteArray as local variable, or maybe I can clear it everytime run re-loops can I?

I do not understand when you note I do not use threads at all. I am giving you a snippet code attached. I omitted timer with one thread instead. There is no other way, the serial device is LECOM, the thread or TImer cannot simply write and return, it needs to wait until it receives packet from serial and then it returns with what it got from the serial.

I made the code very very short and useful, please have a look. I want to know your opinion about how to get rid of these problems.
I note again, that the code works very fine with Timer, the only problem is that when it slows down the input, the pc is a intel Series PC, it is very weak. when the timer write and wait for the reads this causes input to have a 1 second delay. (UI input)
thanks

mcarter
23rd April 2013, 21:31
Not sure what you are trying to accomplish with the static defined in the header file (static RS rs_plc;).
The static means that there will be one copy of 'rs_plc' created for each source file it is included in, is that what you want?
Is that the reason the fileno is 0 or unavailable?

wysota
24th April 2013, 00:01
I cannot simply omit char* and use QByteArray as local variable
Why not?


I do not understand when you note I do not use threads at all. I am giving you a snippet code attached.
I still see no use for threads.


it needs to wait until it receives packet from serial and then it returns with what it got from the serial.
No, it doesn't. First you can check to see if there is anything waiting in the port to be read. If not, there is no point in trying to read since there is nothing there. Alternatively you can set your port to non-blocking mode and try to read anyway. You'll get an error and can carry on. There are many approaches you can take.


I made the code very very short and useful, please have a look.
For me "short" means max 50 lines of code :) Your code is bloated and highly C-ish. And the static variable in the header file indeed looks horrible :)


I want to know your opinion about how to get rid of these problems.
Here is my opinion, read this: http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html

saman_artorious
24th April 2013, 11:51
No, it doesn't. First you can check to see if there is anything waiting in the port to be read. If not, there is no point in trying to read since there is nothing there. Alternatively you can set your port to non-blocking mode and try to read anyway. You'll get an error and can carry on. There are many approaches you can take.

I am also not interested in threads if timers do not slow down system speed in my case. thanks for the book, I will definitely have a look, but for now, if I can run this C-ish code without threads, it values most.

I also tried opening fd in non block mode, but the speed is again slow.


fd = open(portPath, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK, S_IWUSR | S_IRUSR | S_IXUSR);

what am i missing? and i do not understand when you say I should read from it when there is something there. Of course almost always when I write, I immediately get something from serial, it has been designed this way.

wysota
24th April 2013, 17:53
Timers do not slow down anything. And you don't need them too, anyway.