質問

I need to have a class with one activity that is performed once per 5 seconds in its own thread. It is a web service one, so it needs an endpoint to be specified. During the object runtime the main thread can change the endpoint. This is my class:

class Worker
{
    public:
    void setEndpoint(const std::string& endpoint); 

    private:
    void activity (void);

    mutex endpoint_mutex;
    volatile std::auto_ptr<std::string> newEndpoint;

    WebServiceClient client;
} 

Does the newEndpoint object need to be declared volatile? I would certainly do it if the read was in some loop (to make the complier not optimize it out), but here I don't know.

In each run the activity() function checks for a new endpoint (if a new one is there, then passes it to the client and perform some reconnection steps) and do its work.

void Worker::activity(void)
{
    endpoint_mutex.lock(); //don't consider exceptions
    std::auto_ptr<std::string>& ep = const_cast<std::auto_ptr<string> >(newEndpoint);
    if (NULL != ep.get())
    {
        client.setEndpoint(*ep);
        ep.reset(NULL);
        endpoint_mutex.unlock();
        client.doReconnectionStuff();
        client.doReconnectionStuff2();
    }
    else
    {
        endpoint_mutex.unlock();
    }

    client.doSomeStuff();
    client.doAnotherStuff();
    .....
}

I lock the mutex, which means that the newEndpoint object cannot change anymore, so I remove the volatile class specification to be able to invoke const methods.

The setEndpoint method (called from another threads):

void Worker::setEndpoint(const std::string& endpoint)
{
    endpoint_mutex.lock(); //again - don't consider exceptions
    std::auto_ptr<std::string>& ep = const_cast<std::auto_ptr<string> >(newEndpoint);
    ep.reset(new std::string(endpoint);
    endpoint_mutex.unlock();
}

Is this thing thread safe? If not, what is the problem? Do I need the newEndpoint object to be volatile?

役に立ちましたか?

解決

volatile is used in the following cases per MSDN:

The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread.

Objects declared as volatile are not used in certain optimizations because their values can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if a previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

The question in your case is, how often does your NewEndPoint actually change? You create a connection in thread A, and then you do some work. While this is going on, nothing else can fiddle with your endpoint, as it is locked by a mutex. So, per my analysis, and from what I can see in your code, this variable doesn't necessarily change enough.

I cannot see the call site of your class, so I don't know if you are using the same class instance 100 times or more, or if you are creating new objects.

This is the kind of analysis you need to make when asking whether something should be volatile or not.

Also, on your thread-safety, what happens in these functions:

 client.doReconnectionStuff();
 client.doReconnectionStuff2();

Are they using any of the shared state from your Worker class? Are they sharing and modifying any other state use by another thread? If yes, you need to do the appropriate synchronization.

If not, then you're ok.

Threading requires some thinking, you need to ask yourself these questions. You need to look at all state and wonder whether or not you're sharing. If you're dealing with pointers, then you need wonder who own's the pointer, and whether you're ever sharing it amongst threads, accidentally or not, and act accordingly. If you pass a pointer to a function that is run in a different thread, then you're sharing the object that the pointer points to. If you then alter what it points to in this new thread, you are sharing and need to synchronize.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top