在关键代码上使用互斥锁

时间:2013-02-07 14:16:33

标签: c multithreading

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

我将通道作为传递给入口函数的数据传递。但是,这不是一个副本,所以我真的不需要担心吗?

4 个答案:

答案 0 :(得分:3)

规则是:

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

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

3)仅读取(未修改)的数据不需要锁定。这包括"Channel id [ %d ] ..."格式字符串(应将其视为常量)等内容。

4)只能由一个线程访问的数据不需要锁定。这包括函数参数和局部变量等内容。

5)细粒度锁定优于粗粒度锁定。例如,通常您可以将大型数据结构拆分为许多具有多个锁的较小结构,而不是将一个大型数据结构与一个锁分开。

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

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

对于规则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有所帮助。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

但是,如果你想使用线程并行工作,那么拥有一个很长的工作时间并保持锁定会毫无意义。更精细的谷物锁定会更好 - 但这当然假设完成的整体操作可以分成多个部分,使数据保持一致状态。