0

独自のスレッドで 5 秒に 1 回実行される 1 つのアクティビティを持つクラスが必要です。これは Web サービスであるため、エンドポイントを指定する必要があります。オブジェクトの実行時に、メイン スレッドはエンドポイントを変更できます。これは私のクラスです:

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;
} 

newEndpoint オブジェクトは volatile と宣言する必要がありますか? 読み取りが何らかのループにある場合(コンパイラーが最適化しないようにするため)は確かにそれを行いますが、ここではわかりません。

実行ごとに、activity()関数は新しいエンドポイントをチェックし (新しいエンドポイントがある場合は、それをクライアントに渡し、いくつかの再接続手順を実行します)、その作業を行います。

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();
    .....
}

ミューテックスをロックします。つまり、newEndpoint オブジェクトは変更できなくなります。そのため、constメソッドを呼び出せるようにvolatileクラスの仕様を削除します。

setEndpoint メソッド (別のスレッドから呼び出されます):

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();
}

これはスレッドセーフですか?そうでない場合、何が問題ですか?newEndpoint オブジェクトを揮発性にする必要がありますか?

4

1 に答える 1

1

volatileMSDNごとに次の場合に使用されます。

volatileキーワードは、オペレーティングシステム、ハードウェア、または同時に実行されるスレッドなどによって、プログラム内でオブジェクトを変更できることを宣言するために使用される型修飾子です。

として宣言されたオブジェクトは、値がいつでも変更される可能性がvolatileあるため、特定の最適化では使用されません。前の命令が同じオブジェクトから値を要求した場合でも、システムは常に、要求された時点で揮発性オブジェクトの現在の値を読み取ります。また、オブジェクトの値は割り当て直後に書き込まれます。

NewEndPointあなたの場合の問題は、あなたが実際にどのくらいの頻度で変わるかということです。スレッドAで接続を作成してから、いくつかの作業を行います。これが行われている間、エンドポイントはミューテックスによってロックされているため、他に何もエンドポイントをいじることはできません。したがって、私の分析によれば、そしてあなたのコードで見ることができることから、この変数は必ずしも十分に変化するわけではありません。

クラスの呼び出しサイトが表示されないため、同じクラスインスタンスを100回以上使用しているのか、新しいオブジェクトを作成しているのかわかりません。

これは、何かをすべきかどうかを尋ねるときに行う必要のある種類の分析ですvolatile

また、スレッドセーフでは、これらの関数で何が起こりますか。

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

彼らはあなたのWorkerクラスの共有状態のいずれかを使用していますか?彼らは別のスレッドによる他の状態の使用を共有および変更していますか?はいの場合、適切な同期を行う必要があります。

そうでなければ、あなたは大丈夫です。

糸脱毛にはある程度の思考が必要です。これらの質問を自問する必要があります。あなたはすべての状態を見て、あなたが共有しているかどうか疑問に思う必要があります。ポインタを扱っている場合は、ポインタを誰が所有しているのか、誤ってスレッド間でポインタを共有していないかどうかを考え、それに応じて行動する必要があります。別のスレッドで実行されている関数へのポインターを渡すと、ポインターが指すオブジェクトを共有していることになります。次に、この新しいスレッドでポイントするものを変更すると、共有しているため、同期する必要があります。

于 2012-01-29T11:21:36.493 に答える