gcc 4.7.2
c89
Hello,
I am just wondering about applying a mutex lock for the following code snippet.
Is there any rules that you should following, as I don’t want to lock as this would block other threads in this function. As this would really slow things down.
I am compiling with the following CFLAGS:
-Wall -Wextra -g -m32 -O2 -D_DEBUG -D_THREAD_SAFE -D_REENTRANT -D_LARGEFILE64_SOURCE
Code snippet
static void* APR_THREAD_FUNC timeout_duration(apr_thread_t *thd, void *data)
{
apr_status_t rv = 0;
channel_t *channel = NULL;
/*
APPLY LOCK HERE
*/
channel = (channel_t*)data;
/* simulate some work */
apr_sleep(5000000);
LOG_INFO("Channel id [ %d ] Channel name [ %s ] Delay time [ %d ]",
channel->id,
channel->name,
(apr_int32_t)channel->delay_time);
/*
UNLOCK HERE
*/
return NULL;
}
I pass channel as the data that is passed into the entry function. However, isn’t this just a copy so I don’t really need to worry about it?
The rules are:
1) Locks protect data and not code. When data is protected by a lock, code that accesses that data must acquire the data’s lock.
2) Locks should be acquired as late as possible and released as early as possible. This can include shifting work from inside the critical section to outside the critical section.
3) Data that is only read (and not modified) doesn’t need a lock. This includes things like
"Channel id [ %d ] ..."format strings (which should be treated as constant).4) Data that can only be accessed by one thread doesn’t need a lock. This includes things like function parameters and local variables.
5) Finer grained locking is better than coarse grained locking. For example, rather than having one large data structure with one lock, often you can split that large data structure into many smaller structures with many locks.
6) If any code needs more than one lock at a time, you need to define a “locking order”. For example, if one thread acquires lock A then lock B, does some work then releases the locks; and if another thread acquires lock B then lock A, does some work then release the locks; then you can get deadlock (each thread has one lock but needs both to continue). Defining a “locking order” (e.g. saying that lock A must be acquired before lock B) prevents this sort of bug.
For your code, the first few lines don’t need a lock at all because they only access function parameters and local variables (rule 4). The data pointed to by
void *datamay or may not need a lock depending on what it is – e.g. if each thread has its own separate data (rule 4), or if that data is only read (rule 3), then no lock is needed. For theLOG_INFO()function no additional lock is needed (excluding thevoid *datalock if it exists) in the code you posted, but it may have its own internal lock (e.g. to protect a shared log).For an example of rule 2, if the
LOCK_INFOtakes a little while your code could do something like this to release the first lock earlier:Also note that if
LOCK_INFO()uses a lock, releasing the first lock earlier will also help with rule 6.