繁体   English   中英

为什么在一个线程中锁定互斥锁会减慢另一个线程的速度?

[英]Why does locking a mutex in one thread slow down another thread?

我在将mutex引入我的应用程序以启用多线程兼容性的过程中遇到了一些问题。

我有一个线程用于构建用户数据,另一个线程用于渲染数据。 让我们将这两个线程称为thread-1thread-2

  1. 我在thread-1中创建了数据
  2. 然后调用 lock() 并将数据推送到数组中,
  3. 然后在thread-1上调用 unlock()
  4. 然后尝试使用以下步骤从thread-2读取thread-1中写入的数据:
  5. thread-2上调用 lock()
  6. 循环数组显示用户数据
  7. thread-2中调用 unlock()

由于thread-2thread-1快,因此会导致渲染过程出现延迟。 thread-2中删除lock()unlock()解决了这个问题。

谁能解释一下这是什么原因?

你可以试试自旋锁,自旋锁可以用在线程在短时间内有更多的频率切换和更多的计算任务的情况下,自旋锁使线程自己循环而不是休眠,下面是示例代码,你可以在你的机器上运行并检查结果:

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <sys/time.h>

pthread_mutex_t mutex;
pthread_spinlock_t spinlock;

pthread_t tid_1;
pthread_t tid_2;

using namespace std;

#define LOOP_NUM 100000

#define MUTEX_LOCK

#ifdef MUTEX_LOCK

void* thread_func(void *param) {

    int *p = (int *)param;
    int i = 0;
    while( i++ < LOOP_NUM) {

      pthread_mutex_lock(&mutex);

      std::cout << ++(*p) << std::endl;

      pthread_mutex_unlock(&mutex);
    }
}

#else

void* thread_func(void *param) {

    int *p = (int *)param;
    int i = 0;
    while( i++ < LOOP_NUM) {

      pthread_spin_lock(&spinlock);

      std::cout << ++(*p)  << std::endl;

      pthread_spin_unlock(&spinlock);
    }
}

#endif


int main() {

    int i = 0;

    struct timeval tv_start;
    struct timeval tv_end;

    gettimeofday(&tv_start, NULL);

#ifdef MUTEX_LOCK
    pthread_mutex_init(&mutex, NULL);
#else    
    pthread_spin_init(&spinlock, 0);
#endif    

    pthread_create(&tid_1, NULL, thread_func, &i);

    pthread_create(&tid_2, NULL, thread_func, &i);

    pthread_join(tid_1, NULL);
    pthread_join(tid_2, NULL);

    gettimeofday(&tv_end, NULL);

    std::cout<< "spend time:" << (tv_end.tv_sec-tv_start.tv_sec) * 1000 \
    + (tv_end.tv_usec - tv_start.tv_usec)/1000  << " ms" << std::endl;

#ifdef MUTEX_LOCK
    pthread_mutex_destroy(&mutex);
#else
    pthread_spin_destroy(&spinlock);
#endif        


}

这是结果,当我通过互斥锁(毫秒)运行 10 次时:6156 5989 5851 5489 8249 6215 5921 6361 6346 6434

这是使用自旋锁(毫秒)的结果:5434 4489 4713 5519 4868 4832 5287 5670 5270 5200

你会发现使用自旋锁比互斥锁快,在我的机器上将近 1 秒。

如果您还没有这样做,您应该测量每个线程在互斥锁锁定的情况下花费了多少时间,并尽可能减少该时间量。 这将减少其他线程可能必须花费等待获取锁的时间。

将任一线程花费在锁上的时间最小化的一种直接方法是使用双缓冲,即为每个线程提供自己的私有数据结构,以及在两个线程之间共享并由互斥体。

然后,而不是每个线程做:

1. lock mutex
2. read or write to data-structure (which could take some time)
3. unlock mutex

...你的作家会这样做:

1. Write new data to writer's private data-structure (which could take some time)
2. lock mutex
3. swap writer's private data structure with shared data structure (fast!)
4. unlock mutex 
5. clear writer's private data structure

...你的读者会这样做:

1. clear reader's private data structure
2. lock mutex
3. swap reader's private data structure with shared data structure (fast)
4. unlock mutex
5. Use data in reader's private data structure (which could take some time)

大多数数据结构可以在 O(1) 时间内进行交换操作(即只交换两个内部指针),因此这使得锁争用在所有情况下都极少。 (如果您的性能要求如此精细以至于即使进行上下文切换也是一个潜在问题,您可以进一步 go 并用自旋锁替换互斥锁,但在大多数情况下,这并不是绝对必要的)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM