Reputation: 10519
//Thread 1
std::uint64_t getAndResetProcessingTimeInMicro()
{
auto value = m_cumulatedProcessingTimeCount.load(boost::memory_order_acquire);
if (value == 0)
return 0;
auto processingTime = m_cumulatedProcessingTime.load(boost::memory_order_relaxed);
resetProcessingTimeInMicro();
return processingTime / value;
}
//Thread 2
void addProcessingTimeInMicro(std::uint64_t processedTime)
{
m_cumulatedProcessingTime.fetch_add(processedTime, boost::memory_order_relaxed);
//ctxt switch here //-----HERE------
m_cumulatedProcessingTimeCount.fetch_add(1, boost::memory_order_release);
}
Thread1 compute the average of the processing time, Thread 2 accumulate processing time.
I would like to get the insurance that a context switch can't corrompt the data at HERE place without introduce a lock, can I achieve this result by using atomic object ?
Upvotes: 1
Views: 1585
Reputation: 182885
You can, but you probably don't want to.
You need an atomic shared_ptr to the struct that holds both variables. The process for reading is just to copy the shared_ptr
atomically and look at the struct it points to. The process for writing is:
Read the atomic shared_ptr
.
Allocate (using std::make_shared
) a new struct containing the new values for both variables based on the ones in the struct.
Attempt an atomic compare/exchange to set the atomic shared_ptr to point to your new struct.
If the compare/exchange succeeds, you are done.
Free the new structure you created and go back to step 1. (You are guaranteed some other writer made forward progress.)
You really don't want to do this though. Just use a lock.
Upvotes: 1
Reputation: 5344
make a union like this:
union CData {
struct {
__int32 a;
__int16 c;
__int16 d:2,
e:14;
// you get the idea...
}
__int64 n64;
}
Use all the variables using the struct members, do the atomic stuff with n64.
Upvotes: 0
Reputation: 11968
If you want to do two different atomic operations together you need a mutex both when you write and when you read them. Mutexes don't prevent context switches, but used this way guarantee that you don't access half updated states.
Alternatively, if you really don't want to use a mutex, you could use some of the 64 bits of a single uint64_t to store the count (say the lower 8). Then you would
m_cumulatedProcessingTime.fetch_add((processedTime << 8) + 1, boost::memory_order_release);
and then retrieve it
auto value = m_cumulatedProcessingTimeCount.load(boost::memory_order_acquire);
auto time = value >> 8;
auto count = value & 0xff;
Upvotes: 2