• Advertisement

Recommended Posts

How can i create a thread that executes a function (void) in a class, cause

void foo() {}

int main()
{
std::thread first (foo); 
}

works

 

but
 

struct TTCPServer
{
void foo() {}
void CreateThread()
{
std::thread first (foo); 
}
};

 

doesnt even compile

Edited by Cat's machete

Share this post


Link to post
Share on other sites
Advertisement
#include <functional>
#include <thread>

struct TTCPServer {
    void foo() {}
    void CreateThread() {
        std::thread first(std::bind(&TTCPServer::foo, this)); 
    }
};

int main() {};

https://wandbox.org/permlink/6IODSGQnzTtm5QhU

"this" is always passed as an implicit argument of the member method. You must bind all arguments of the member method.

Edited by matt77hias

Share this post


Link to post
Share on other sites

yeah i just went here to write the same thing i figoured that out myself thanks man

listen_and_accept_finished = false;

std::thread ListenThread(&TTCPWindowLayerServer::ListenAndAccept, this);

 

however using your code or mine makes my app to crash

theres an int i increment each time thread loop executes

 

void ListenAndAccept()
{
	while (!listen_and_accept_finished)
	{
		Port = Port + 1;
		continue;
    }
}

and it just crashes after few iterations

 

i dont even use int Port; anywhere else except during class constructor to define it as 0

listen_and_accept_finished isnt used anywhere else than in this loop too

 

i get

Fatal signal 6 (SIGABRT)
 

it may seem that android doesnt like threads...

Share this post


Link to post
Share on other sites
30 minutes ago, Cat's machete said:

and it just crashes after few iterations

You only invoke CreateThread once, I suppose? I am not really into <thread>, but shouldn't listen_and_accept_finished (and Port) be volatile, since they will be modified outside the thread? Though in any case, I am not sure why it would crash.

#include <functional>
#include <iostream>
#include <thread>

struct TTCPServer {
    volatile bool listen_and_accept_finished = false;
    volatile int port = 0;
    
    void ListenAndAccept() {
       while (!listen_and_accept_finished && port < 10) {
           std::cout << port++ << std::endl;
       }
    }
    
    std::thread CreateThread() {
        return std::thread(std::bind(&TTCPServer::ListenAndAccept, this)); 
    }
};

int main() {
    TTCPServer server;
    server.CreateThread().join();
};

https://wandbox.org/permlink/A8cZoSbv6wM9BST8

Edited by matt77hias

Share this post


Link to post
Share on other sites
5 minutes ago, Cat's machete said:

funniest thing is whenever i add ListenThread.join(); and create exit condition so thread actually quits it doesnt crash anything.

As I understand you correctly, you execute something like my code above without invoking "join" on the "std::thread"? In this case your main thread will finish, destroy the TTCPServer on the stack which causes the captured "this" pointer of your std::thread to become invalid, resulting in undefined behavior.

Edited by matt77hias

Share this post


Link to post
Share on other sites

this is why i do this:

TTCPWindowLayerServer * srvtcp = new TTCPWindowLayerServer();
    srvtcp->CreateServer(0);

 

 

i dont want to call join cause i don't want the main thread to be paused at all,

 

however it may seem that android automatically crashes my app, since i think it thinks the UI Thread is being suspended, thus how is this even possible, when i spawn a thread so it shouldnt matter from which place i spawn it, it should independly even when im creating server class in that ui thread, but if it is so, then i just grab my pc and throw it into river.

looks like you cant stall ui thread with some standard function even for 20 seconds, but you cant stall it with a thread for even a microsecond., and my app base is always dependnt on ui thread since i call onTap(x, y) from java to execute cpp code.....

 

either i thro pc and phones to the river or make a bypass by using join and somehow proceed with stalled threads. giving up seems easier

Edited by Cat's machete

Share this post


Link to post
Share on other sites
27 minutes ago, Cat's machete said:

i dont want to call join cause i don't want the main thread to be paused at all,

I know, but in the end you want your application including all its threads to be terminated properly. I just added it to have a correct example. :)

Edited by matt77hias

Share this post


Link to post
Share on other sites

i have read cpp reference more carefully and found that detach does not kill the thread but makes it independent from creator thread, so this is my saint graal

 

Detaches the thread represented by the object from the calling thread, allowing them to execute independently from each other.

Both threads continue without blocking nor synchronizing in any way. Note that when either one ends execution, its resources are released.

After a call to this function, the thread object becomes non-joinable and can be destroyed safely.

 

 

jeez i almost threw all my phones down the river ;p

Share this post


Link to post
Share on other sites

It might work at the moment, but as soon as your thread does something interesting, it will likely need to communicate with other parts of your program.

Depending on how that is implemented, you could re-introduce the crashes.

Share this post


Link to post
Share on other sites

Small note on this.

Quote

but shouldn't listen_and_accept_finished (and Port) be volatile, since they will be modified outside the thread

That is correct, but FWIW, with C++11+ I've used std::atomic for situations where multiple threads are accessing simple data types. You can use the std::memory_order_* operations for further control.

 

Share this post


Link to post
Share on other sites
14 hours ago, frob said:

Volatile doesn't do what most people think it does.

Well it does what my intent was: not caching the value. Though, you're right that atomics will result in far superior performance. For non-primitive types, (mutex or even spin) locking is probably faster than volatile as well. :)

Edited by matt77hias

Share this post


Link to post
Share on other sites
On 2/6/2018 at 1:17 PM, matt77hias said:

Well it does what my intent was: not caching the value. Though, you're right that atomics will result in far superior performance. For non-primitive types, (mutex or even spin) locking is probably faster than volatile as well. :)

Volatile is both too much and not enough for multi-threaded synchronization.

Volatile prevents the compiler from putting a value in a register, and it makes the compiler treat reads and writes as IO for ordering purposes. But what it does not to is provide memory fences to prevent the processor from reordering synchronization instructions. Therefore, using atomics (with sequentially consistent memory order) will actually generate different assembly then using volatile. On weaker processor architectures, the difference is more pronounced, but even x64 now has Non-Temporal SSE instructions, which need more fences.

And technically, any program that has a shared data not synchronized by threading primitives (which volatile isn't), is undefined.

Share this post


Link to post
Share on other sites
2 hours ago, King Mir said:

... and not enough for multi-threaded synchronization.

This why Microsoft has these InterlockedX functions (e.g. InterlockAdd), isn't?

Though, these functions are said to be atomic, the values are still volatile. Doesn't the latter always impose a bottleneck?

Share this post


Link to post
Share on other sites

Yes, it does look like InterlockedAdd would get you the rest of the way, based on a quick look. But why wouldn't you just use std::atomic<T>? Especially if using std::thread.

Also, a complication here is that Microsoft's compiler by default implements volatile as atomic, adding those fences that the language does not require it to.

Share this post


Link to post
Share on other sites
3 hours ago, swiftcoder said:

My hunch is that their compiler is smart enough to omit those fences if used in an actually atomic operation like InterlockAdd... But I don't have the wherewithal to prove that :)

That's backwards. The entire point of using atomic operations is so the compiler adds those fences.

I can't figure out from the linked documentation if InterlockAdd has sequentially consistent semantics, or merely acquire/release semantics, and therefore if it would require a locked instruction, or not on x86. A locked instruction would be sufficient for sequentially consistent semantics on x86, so you don't need a fence.

Edited by King Mir

Share this post


Link to post
Share on other sites
8 hours ago, King Mir said:

I can't figure out from the linked documentation if InterlockAdd has sequentially consistent semantics, or merely acquire/release semantics, and therefore if it would require a locked instruction, or not on x86. A locked instruction would be sufficient for sequentially consistent semantics on x86, so you don't need a fence.

Unless of course the compiler decides to reorder the instructions in your code, or the CPU is superscalar and performs out-of-order and/or speculative execution, and you end up using the results of your interlocked add before actually calling that instruction: a locked processor instruction does not affect that but a fence does.  Then again, you're using this in a multi-threaded application, so you're going to get pre-empted right after your InterlockAdd and the value gets changed by the other thread after you've obtained it, and you're left scratching your head why things don't work, sometimes, maybe.

 

Share this post


Link to post
Share on other sites
4 hours ago, Bregma said:

Unless of course the compiler decides to reorder the instructions in your code, or the CPU is superscalar and performs out-of-order and/or speculative execution, and you end up using the results of your interlocked add before actually calling that instruction: a locked processor instruction does not affect that but a fence does.  Then again, you're using this in a multi-threaded application, so you're going to get pre-empted right after your InterlockAdd and the value gets changed by the other thread after you've obtained it, and you're left scratching your head why things don't work, sometimes, maybe.

 

 

Several things:

  • InterlockedAdd is a compiler intrinsic, for which the compiler is aware of the semantics. As such, the compiler should know not to reorder instructions around it. If you were to implement InterlockedAdd yourself, you are correct that it is possible to get it wrong, if you don't communicate the fencing semantics of an atomic instruction to the compiler. Note, these fencing semantics do not imply an actual fence instruction on every architecture.
  • I would recommend using C/C++ 11 atomics over compiler intrinsics such as these to avoid learning all the nuances of each compilers intrinsics, including InterlockedAdd.
  • As for the processor executing your instruction out of order, I disagree that fences are needed in x86. The proof is here, http://www.cl.cam.ac.uk/~pes20/cpp/popl085ap-sewell.pdf, though I don't claim to have read and understood all of it myself. I believe it shows that a locked instruction is sufficient on all atomic stores to guarantee sequential consistency.
  • You are right that locked instructions do not prevent a value from changing after you have read it, but this does not prevent you from being able to reason about your program having sequential consistency. Yes, you still need correct algorithms that don't assume that a shared value will necessarily still be of the value last read from it, unless otherwise guaranteed in code.

 

Share this post


Link to post
Share on other sites
14 hours ago, King Mir said:

That's backwards. The entire point of using atomic operations is so the compiler adds those fences.

I meant in the opposite direction. If you are using a volatile variable in atomic intrinsics, the compiler may be smart enough to avoid applying the fences in all the non-atomic cases.

Share this post


Link to post
Share on other sites
1 hour ago, swiftcoder said:

I meant in the opposite direction. If you are using a volatile variable in atomic intrinsics, the compiler may be smart enough to avoid applying the fences in all the non-atomic cases.

So if I understand you, what you're saying is that this generates a fence on Visual Studio:

volitile LONG var = 0;
var += 10l;
	

However, you think this won't even though the first argument is volatile:

volatile LONG var = 0;
InterlockedAddNoFence(var, 10l);
	

If so, I think you're right.

Edited by King Mir

Share this post


Link to post
Share on other sites
On 05/02/2018 at 8:41 AM, Cat's machete said:

funniest thing is whenever i add ListenThread.join(); and create exit condition so thread actually quits it doesnt crash anything.

That's by design. std::thread::~thread is calling std::terminate(). So, either join() with the thread, or detach() it if you're 100% sure that's what you need.

Share this post


Link to post
Share on other sites

Note that even though that isn't required, it is something that Microsoft has chosen to do beyond what the standard requires.

It is non-standard behavior, but they do it because too many programs have misused the old behavior in bug-inducing ways.  It adds a performance penalty so use with caution.

As I mentioned in my earlier posts, old code that correctly relied on the behavior in decades past would often use object aliases for both a volatile version and a non-volatile version. Tricky to get right and disastrous to get wrong, it can eliminate some of the performance issues.

Or, you can use tools recognized by the language and compiler for the correct behavior which is the better choice in modern code.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Advertisement