1

I am working a linux server using epoll. I have this code to read buffer

 int str_len = read(m_events[i].data.fd, buf, BUF_SIZE);

 if (str_len == 0) {
      if (!removeClient(m_events[i].data.fd))
          break;
      close(m_events[i].data.fd);
 } else {
      char *pdata = buf;
      pushWork(pdata);
 }

buf is declared like this

buf[BUF_SIZE]

pushWork function declared like this

 pushWork(char *pdata){
     push pdata to the thread pool's queue 
 }

Firt of all, I think char *pdata = buf has a problem since it just points to the buffer and the buffer will be overriden whenever a new data comes in. So do I need to memcpy?

Also, is there any other nice way to handle this in c++ ? This code is kind of c style I think I have a better way to do this in c++.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
codereviewanskquestions
  • 13,460
  • 29
  • 98
  • 167

3 Answers3

2

is there any other nice way to handle this in c++ ? This code is kind of c style I think I have a better way to do this in c++

Like I suggested in one of your previous questions, the Boost.Asio library is the de-facto C++ networking library. I strongly suggest you spend some time reading about it and studying the examples if you are writing a C++ networking application.

Community
  • 1
  • 1
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
0

That way is bad because you have only one buf, meaning that you can only have one thread at a time working on it, so you are not using threads like they should be used.

What you can do is malloc() a buffer, copy the payload to that malloc'd buffer and pass it to the thread and let the thread free that buffer once it's done with it. Just be sure to free it or else there will be memory leaks.

example code:

char * p;

p = (char *)malloc(str_len+1);
memcpy(p, buf, str_len+1);

pushWork(p); //free p inside, after use.
Vinicius Kamakura
  • 7,665
  • 1
  • 29
  • 43
0

You will need to do a memcpy (or something equivalent) unless you can make it so that the data in (buf) is never needed after pushWork() returns. If you can afford to all the processing of the buffer's data inside pushWork(), OTOH, no copying of the buffer is necessary.

Another alternative would be to allocate a buffer off the heap in advance each time therough the epoll loop, and read() directly into that buffer instead of reading into a buffer on the stack... that way the dynamically allocated buffer would still be available for use ever after the event loop goes on to other things. Note that doing this would open the door to possible memory leaks or memory exhaustion though, so you'd need to be careful to avoid those issues.

As far as a "C++ way" to do this, I'm sure there are some, but I don't know that they will necessarily improve your program. The C way works fine, why fix what isn't broken?

(One other thing to note: if you are using non-blocking I/O, then read() will sometimes read and return fewer than BUF_SIZE bytes, in which case you'll need logic to handle that eventuality. If you are using blocking I/O, OTOH, read() will sometimes block for long periods (e.g. if a client machine dies having sent only half of a buffer) which will block your epoll loop and make it unresponsive for perhaps several minutes. That's a more difficult problem to deal with, which is why I usually end up using non-blocking I/O, even if it is more of a pain to get right.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • 1
    Even blocking I/O can return a short read(), actually. If poll()/select()/epoll() says the descriptor is ready for reading, then read() will not block, no matter how many bytes you request. – Nemo Jun 17 '11 at 01:42
  • @Nemo I think the latter is not quite guaranteed: http://stackoverflow.com/questions/5351994/will-read-ever-block-after-select – Jeremy Friesner Jun 17 '11 at 03:18
  • Then Linux is in violation of the [POSIX spec](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html). "A descriptor shall be considered ready for reading when a call to an input function with O_NONBLOCK clear would not block, whether or not the function would transfer data successfully." [etc.] That answer you link wrong in another way, too: read() on a blocking descriptor can _never_ return 0 except at EOF. – Nemo Jun 17 '11 at 03:55
  • Linux may well be in violation of the POSIX spec. Nevertheless, people who are running under Linux still have to deal with Linux's actual behavior; not the behavior Linux ought to have. – Jeremy Friesner Jun 18 '11 at 05:04
  • Well, I am quite sure read() never returns 0 except at EOF, even on Linux. (That is pretty much the definition of "EOF".) So that other answer is definitely dead wrong about that. As for select(), the only reference we have is to the man page... And I think there is a decent chance the man page is wrong. – Nemo Jun 18 '11 at 05:06