Thread: Attempting to make a threadsafe construct

  1. #1
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138

    Attempting to make a threadsafe construct

    Here's what I'm trying to do, but VS2008 isn't liking my forward declaration of the class (or friend member function for that matter).

    Code:
    #include <iostream>
    
    
    class B;
    
    class A {
    public:
         ...
         friend bool B::memberFunc(A a);
    
    private:
         int _a;
    };
    
    class B {
    public:
         bool memberFunc(A a){
              std::cout<<a._a;
              return true;
         };
    };
    
    int main(int argc, char* argv[])
    {
    
    	A a;
    	B b;
    
    	B.memberFunc(a);
    
    
    	std::cin.get();
    
    	
    	return 0;
    }
    I've tried both permutations of order to no avail. I'm assuming it's because what I'm trying to do isn't legal. My logic is as follows (I'm hoping someone can provide me with a better solution):

    I have class NTS (not threadsafe) which has been implemented previously. Now, the class must be made threadsafe. More specifically, there will be 2 "types" of operations: Updating of the data and rendering of the data. To solve this problem, my solution is to construct a new class TS which possesses two instances of class NTS: _client and _update. Each will do its own thing with periodic syncing of _client's data from _update. I hope to have a member function in TS do this (and be NTS's friend to properly hide the data). Since TS clearly has two instances of NTS as members, one of the classes must be forward declared. Am I doing something syntactically wrong or is there a better paradigm I should be considering?

  2. #2
    Registered User
    Join Date
    Mar 2010
    Posts
    109
    Sounds to me like you need to implement semaphores. I'm not sure what you are trying to achieve by creating two instances of the class. If you are running multiple processes, you will still have timing issues. You need to protect the data that is shared from being accessed simultaneously. Is this an assignment on creating a thread safety mechanism? If not, there are already systems you can use depending on your platform.

  3. #3
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    I probably should have clarified. I understand the need for some sort of data protection such as semaphores, critical sections, etc. I thought it was implicitly assumed one would be used in the sync method. The reason for having two instances of the data is that the _client instance will be doing things other than rendering and can't constantly be locking up the _update instance which will be running a simulation. Thus, a periodic sync seems to be the best bet.

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You need to break things up.
    Code:
    class A;
    
    class B {
    public:
         bool memberFunc(A &a);
    };
    
    class A {
    public:
         friend bool B::memberFunc(A &a);
    
    private:
         int _a;
    };
    
    bool B::memberFunc(A &a)
    {
              std::cout<<a._a;
              return true;
    }
    Note that the memberFunc() needs to accept a reference argument. This prevents an infinitely recursive situation of the definition of class B needing to be visible to the compiler before the definition of class A, and vice versa.

    As to whether your "solution" makes things thread-safe: I doubt it. The key to ensuring thread safety for an object is ensuring that one thread can't modify an object during a time interval when another is accessing (reading or modifying) it. It is therefore necessary to ensure that the instances of the class at not "doing their thing" during the sync operation. That means either the sync operation happens while the objects are known not to be "doing their thing", or some means of forcing the objects to stop during the sync operation.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    Don't worry so much about the thread-safety. I know what I'm doing there, and things will be thread-safe. I'm a semi-competent programmer who went on a bit of a hiatus so things are a bit rusty.

    So it turns out my example wasn't exactly as I remembered it (just took a look at the code again) and what I'm trying isn't compiling. So let's try this again...

    Code:
    #include <iostream>
    
    class A;
    
    class B {
    public:
    	 void setA1(int A1);
    	 void copy(void);
    	 void print(void);
    private:
    	 A a1, a2;
    };
    
    class A {
    public:
            friend void B::copy(void);
    	friend void B::setA1(int A1);
    	friend void B::print(void);
    
    private:
            int _a;
    };
    
    
    void B::setA1(int A1)
    {
         a1._a = A1;
    }
    
    void B::copy(void)
    {
         a2._a = a1._a;
    }
    
    void B::print(void)
    {
         std::cout<<a1._a<<" "<<a2._a<<std::endl;
    }
    
    int main(void){
    
    	B b;
    	b.setA1(5);
    	b.copy();
    
    	b.print();
    	std::cin.get();
    	return 0;
    }
    Again doesn't compile. What's the general "rule" here to indicate to the compiler a lack of infinite recursion.

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by golfinguy4 View Post
    Code:
    #include <iostream>
    
    class A;
    
    class B {
    public:
    	 void setA1(int A1);
    	 void copy(void);
    	 void print(void);
    private:
    	 A a1, a2; // You cannot have an instance of A here, since it is not defined yet -- forward declaration is not enough
    };
    
    class A {
    public:
            friend void B::copy(void);
    	friend void B::setA1(int A1);
    	friend void B::print(void);
    
    private:
            int _a;
    };
    Code:
    
    
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  7. #7
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    Thanks brewbuck. I figured what I was doing wasn't legal, and your response confirms it. Is there an equivalent paradigm with similar encapsulation (i.e. maintaining the hidden nature of the data in A)?

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    If you are unable or unwilling to have a definition of A at that point, then you can only contain a pointer to A, not an actual A object.

  9. #9
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    And that's what I was looking for. Thanks.

  10. #10
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    (void) is unnecesary in C++. Just use ()
    Don't use variables starting with an underscore then a lowercase letter. IIRC that's reserved for the compiler.
    Why don't you just make the the whole class B a friend of class A?
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by golfinguy4 View Post
    Don't worry so much about the thread-safety. I know what I'm doing there, and things will be thread-safe. I'm a semi-competent programmer who went on a bit of a hiatus so things are a bit rusty.
    No offense to you, but that is honestly the worst attitude one can have.
    If people have advice, you should really listen to them before deciding that you don't need them (and even so, you should really consider the implications of they've said).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Note that the memberFunc() needs to accept a reference argument. This prevents an infinitely recursive situation of the definition of class B needing to be visible to the compiler before the definition of class A, and vice versa.
    I don't think this is so, if OP wants to pass by value. It is just a declaration and happy with an incomplete type.

    Otherwise, yes, I don't see why it shouldn't be laid out like this. (The key to breaking circular dependencies is that you'll need to separate declarations and implementations.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  13. #13
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    Quote Originally Posted by iMalc View Post
    (void) is unnecesary in C++. Just use ()
    Don't use variables starting with an underscore then a lowercase letter. IIRC that's reserved for the compiler.
    Why don't you just make the the whole class B a friend of class A?
    i believe that's double underscore.

    had that one bite me 2 yrs ago...

  14. #14
    The larch
    Join Date
    May 2006
    Posts
    3,573
    i believe that's double underscore.
    Or single underscore in front of capital letters, if I'm not mistaken.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  15. #15
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Bah, I was going by what people said last time this came up. I avoid anything starting with underscores, and don't really care whether I have to avoid 1, 2, or even 3 of them, followed by upper lower or camel case. There's just no need for starting variable names with them.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Makefile Problem: None rule to make target
    By chris24300 in forum Linux Programming
    Replies: 25
    Last Post: 06-17-2009, 09:45 AM
  2. Establishing 'make clean' with GNU make
    By Jesdisciple in forum C Programming
    Replies: 9
    Last Post: 04-11-2009, 09:10 AM
  3. How to make a Packet sniffer/filter?
    By shown in forum C++ Programming
    Replies: 2
    Last Post: 02-22-2009, 09:51 PM
  4. HELP!wanting to make full screen game windowed
    By rented in forum Game Programming
    Replies: 3
    Last Post: 06-11-2004, 04:19 AM
  5. make all rule
    By duffy in forum C Programming
    Replies: 9
    Last Post: 09-11-2003, 01:05 PM