I understand that shared variables should be locked when multiple threads are reading or writing it at the same time to avoid concurrency issue. However, in a single writer multiple reader environment, I suspect the necessity for the writer thread to lock that variable when it is reading from it. My reasoning is that since it is the only writer, no other threads might modify the content, so it is impossible to get undefined behavior.
In other words, is read lock really necessary in my_read_1
? What are the consequences if it is omitted?
/********* Thread A *********/
hlist_head_t g_my_table[MY_TABLE_SIZE];
pthread_rwlock_t g_my_lock;
void my_update(uint64_t hash, hlist_node_t *node)
{
pthread_rwlock_wrlock(&g_my_lock);
hlist_head_t *head = &g_my_table[hash % MY_TABLE_SIZE];
hlist_add_head(node, head);
pthread_rwlock_unlock(&g_my_lock);
}
void my_read_1(uint64_t hash)
{
// TODO: is read lock necessary here?
hlist_head_t *head = &g_my_table[hash % MY_TABLE_SIZE];
if (hlist_empty(head)) {
printf("empty\n");
} else {
printf("%p %p\n", head->first->next, head->first->pprev);
}
}
/********* Thread B *********/
extern hlist_head_t g_my_table[MY_TABLE_SIZE];
extern pthread_rwlock_t g_my_lock;
void my_read_2(uint64_t hash)
{
pthread_rwlock_rdlock(&g_my_lock);
hlist_head_t *head = &g_my_table[hash % MY_TABLE_SIZE];
if (hlist_empty(head)) {
printf("empty\n");
} else {
printf("%p %p\n", head->first->next, head->first->pprev);
}
pthread_rwlock_unlock(&g_my_lock);
}
In other words, is read lock really necessary in my_read_1 ? What are the consequences if it is omitted?
The requirement that must be satisfied is that every pair of accesses (reads or writes) to an object must be properly ordered if at least one of them is a write. The limitation of this requirement to the cases where at least one access is a write is what makes read / write locks sensible -- reads don't need to be synchronized with respect to each other, only with respect to writes.
Accesses by different threads are ordered via synchronization objects, such as locks. A read / write lock provides for ordering pairs of writes and pairs of one read and one write, without requiring or providing for ordering of pairs of reads. This can be advantageous.
But notwithstanding the general use of locking by a program, every pair of access by the same thread is ordered by the single-thread execution order of the program, so a thread does not need to use locking to order its own reads and writes with respect to each other. Therefore, if only one thread ever writes to the shared data then that thread does not need to use locking to protect its reads of that data.