2013-02-07 57 views
1
gcc 4.7.2 
c89 

你好使用互斥锁,关键代码

我只是想知道如何申请互斥锁下面的代码片段。

是否有任何规则应该遵循,因为我不想锁定,因为这会阻止此函数中的其他线程。因为这会让事情减缓。

我用下面的CFLAGS编译:

-Wall -Wextra -g -m32 -O2 -D_DEBUG -D_THREAD_SAFE -D_REENTRANT -D_LARGEFILE64_SOURCE 

代码片断

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

我通过通道作为传递到输入功能的数据。但是,这不仅仅是一个副本,所以我不需要担心它?

+0

ptr!=副本数据的副本。 –

回答

2

的规则是:

1)锁保护数据,而不是代码。当数据受锁保护时,访问该数据的代码必须获取数据的锁。

2)锁应尽可能早地获得并尽早释放。这可以包括将工作从关键部分转移到关键部分之外。

3)只读(而不是修改)的数据不需要锁。这包括诸如"Channel id [ %d ] ..."格式字符串(应被视为常量)之类的内容。

4)只能由一个线程访问的数据不需要锁定。这包括诸如函数参数和局部变量之类的东西。 5)细粒度锁定优于粗粒度锁定。例如,不是让一个大型数据结构具有一个锁,通常可以将该大型数据结构拆分为许多具有多个锁的较小结构。

6)如果任何代码一次需要多个锁,则需要定义一个“锁定顺序”。例如,如果一个线程获取锁A然后锁B,则执行一些工作然后释放锁;如果另一个线程获取了锁B,然后锁定A,则执行一些工作然后释放锁;那么你可能会死锁(每个线程有一个锁,但需要两个继续)。定义一个“锁定顺序”(例如说在锁B之前必须获取锁A)可以防止这种错误。

对于您的代码,头几行根本不需要锁,因为它们只访问函数参数和局部变量(规则4)。 void *data指向的数据可能需要也可能不需要锁,具体取决于它是什么 - 例如,如果每个线程都有自己独立的数据(规则4),或者只有该数据被读取(规则3),则不需要锁定。对于LOG_INFO()函数,在您发布的代码中不需要额外的锁(不存在void *data锁),但它可能有自己的内部锁(例如保护共享日志)。

对于规则2的例子,如果LOCK_INFO需要一点时间你的代码可以做这样的事情在第一锁较早释放:

temp_ID = channel->id; 
temp_name = strdup(channel->name); // Should check for NULL! 
temp_delay = channel->delay_time; 

/* 
    UNLOCK HERE 
*/ 

LOG_INFO("Channel id [ %d ] Channel name [ %s ] Delay time [ %d ]", 
     temp_ID, 
     temp_name, 
     temp_delay); 
free(temp_name); 

还要注意的是,如果LOCK_INFO()使用锁,释放第一次锁定也有助于规则6.

+0

Re:3,如果其他线程可能写入,则即使读取也需要锁定。在这种情况下,rwlocks很有用。 –

+0

@R ..是的,但是规则1应该覆盖该规则(例如,如果数据被写入,则数据需要锁;并且使用具有锁的数据的函数必须获取数据的锁,即使该函数只读取数据)。我可能可以做得更清楚。 – Brendan

1

不,它不是一个副本,该data实际上只是一个指针数据,因此,你的线程和调用者的上下文都可以访问此相同数据。现在,如果你可以保证(线程和调用者上下文)不会同时触及数据,那么在线程函数中就不需要锁定了。

1

您绝对需要担心,因为data是指向您的实际channel_t数据的指针。

但是,如果您想使用线程并行工作,那么在锁定时间长的情况下工作时间很长。更好的粒子锁定会更好 - 但是这当然假定所做的整体操作可以分成几部分,使数据保持一致的状态。

2

如果您想在解锁互斥体时读取此通道,请使用pthread_mutex_trylock()而不是pthread_mutex_lock()。它确实相同,但pthread_mutex_trylock()不blocant,基于它的返回值 你可以这样做:

if (pthread_mutex_trylock(your_mutex)) 
{ 
    //Read the data. 
}