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

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

4

4 回答 4

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如果存在则不包括锁),但它可能有自己的内部锁(例如保护共享日志)。

对于规则 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。

于 2013-02-07T14:40:01.783 回答
2

如果您想在互斥锁解锁时读取此通道,请使用 pthread_mutex_trylock() 而不是 pthread_mutex_lock()。它的作用相同,但 pthread_mutex_trylock() 不是 blocant,基于它的返回值,您可以执行以下操作:

if (pthread_mutex_trylock(your_mutex))
{
    //Read the data.
}
于 2013-02-07T14:28:07.717 回答
1

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

于 2013-02-07T14:22:34.227 回答
1

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

但是,如果您想使用线程来并行工作,那么在持有锁的情况下进行很长时间的工作是没有意义的。更细粒度的锁会更好——但这当然假设完成的整体操作可以分成多个部分,使数据保持一致状态。

于 2013-02-07T14:25:06.977 回答