Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: How to stop the socket blocking while it's being used?  (Read 5351 times)

0 Members and 1 Guest are viewing this topic.

Mal1

  • Newbie
  • *
  • Posts: 18
    • View Profile
How to stop the socket blocking while it's being used?
« on: April 02, 2015, 04:16:46 pm »
As the title says, I want to use the sf::UdpSocket in blocking mode, but I need to be able to register signals for exit, and as such I also need a way to set the socket to non-blocking mode, so I can return to the function that it's using it.

if( listenerSocket.receive(packet,clientAddress,port) != sf::Socket::Done || exitSignal )

This is the line that's stopping the program. Well, obivously, it's supposed to, since the socket is set to blocking.
So, everything here is fine and dandy.
Now, I'm trying to get another thread to change the socket's blocking mode, so I can close this function.

I tried just calling
listenerSocket.setBlocking(false);
from a different thread, but it doesn't seem to register it until it gets at least 1 packet while still in the blocking mode.
My question is, is there any other way to unblock this socket than just completely killing the thread it's running in?
« Last Edit: April 02, 2015, 04:38:18 pm by Mal1 »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: How to stop the socket blocking while it's being used?
« Reply #1 on: April 02, 2015, 05:19:14 pm »
Getting into the situation where you have to unblock a thread from another one shows flaws in the design. The only time when that should happen is when using explicit synchronization primitives (which SFML doesn't support).

You have 2 obvious solutions to this and 1 maybe not so obvious one.

The first 2 simply involve getting rid of the block in the first place, either by setting the socket non-blocking or by using an sf::SocketSelector. Either way, you will end up polling for readiness, and I don't see why you don't consider them viable options. Is there a specific reason why you want your sf::UdpSocket to be blocking? Is it a must? Or just something you prefer? The rest of your system design seems to dictate that you should use a non-blocking design, so in the end you won't have a choice anyway.

The 3rd solution, might not be the most elegant and I even consider it a bit "hacky", but in the end it "gets the job done".
(click to show/hide)
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Mal1

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: How to stop the socket blocking while it's being used?
« Reply #2 on: April 02, 2015, 05:38:19 pm »
I'd rather have it blocking, since the non-blocking mode uses 6-7% of cpu during polling. (with an infinite while( true ) loop + no sleep)
Blocking stays at nice 0% and since I'm planning a rather resource intensive program, I don't want it to use any more resources than I absolutely need to.

I'll go with the hacky solution, just implemented it and works pretty much flawlessly. Thank you.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: How to stop the socket blocking while it's being used?
« Reply #3 on: April 02, 2015, 05:55:31 pm »
I'd rather have it blocking, since the non-blocking mode uses 6-7% of cpu during polling. (with an infinite while( true ) loop + no sleep)
Blocking stays at nice 0% and since I'm planning a rather resource intensive program, I don't want it to use any more resources than I absolutely need to.
You know that this is the reason why sf::SocketSelector lets you sleep for a specific amount of time when waiting for sockets to become ready right? 1 millisecond makes no perceivable difference when we are talking about network communication and keeps your CPU close enough to 0% utilization at idle.

And if you think that resource intensive programs should always use blocking sockets to save cycles, then you should have a look at some of the high performance web servers on the internet. Many of them use readiness notification and hardly ever block. Believe it or not, but in really resource intensive scenarios, forcing the operating system to potentially block and unblock a lot in a short period of time actually consumes more CPU than just polling it constantly.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Mal1

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: How to stop the socket blocking while it's being used?
« Reply #4 on: April 02, 2015, 06:01:33 pm »
I see. I might try to do it with the SocketSelector then. Well, I'll see. I get that it's potentially better, but I'd rather focus on other aspects for now. I'll note this down somewhere near this portion of the code and maybe change it up once I get a prototype of my server running.

Thank you for your time

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: How to stop the socket blocking while it's being used?
« Reply #5 on: April 03, 2015, 11:35:06 am »
Getting into the situation where you have to unblock a thread from another one shows flaws in the design.
I don't think this is that uncommon in networking. For example, the sockets in the Android API (Socket, DatagramSocket, BluetoothSocket) provide a close() method which cancels blocking waits in other threads.

Implementing it does indeed require more advanced synchronization primitives, which SFML may not have access to at the moment. But with C++11, we have things like std::condition_variable in the standard library.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: How to stop the socket blocking while it's being used?
« Reply #6 on: April 03, 2015, 04:35:15 pm »
I don't think this is that uncommon in networking. For example, the sockets in the Android API (Socket, DatagramSocket, BluetoothSocket) provide a close() method which cancels blocking waits in other threads.
One could already do this with SFML, just call sf::UdpSocket::unbind() or sf::TcpSocket::disconnect(). They both internally call close().

That doesn't change the fact that this is not an acceptable solution in general, but just for this specific scenario. Simply closing the socket doesn't "unblock" it per se so that it can be reused at a later point. It outright destroys it. This is the reason why I don't categorize it as a solution to the problem, because it relies on side-effects.

On more-or-less POSIX compliant systems (including Android obviously), I/O cancellation has been around for a while, so this should work in most environments. However, I/O cancellation only became widely supported on Windows since Vista. I know people shouldn't be using Windows XP or earlier any more, but this isn't something to simply overlook. Closing a socket that is blocked on an operation can have unpredictable results on platforms that aren't ready for it.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).