【问题标题】:C++ Mutex Lock/UnlockC++ 互斥锁/解锁
【发布时间】:2022-07-31 18:20:36
【问题描述】:

虽然我遇到了一些问题,但我开始在我的应用程序中引入互斥锁以实现多线程兼容性。

我有 1 个线程用于构建用户数据,另一个用于渲染数据的线程让我们调用这个线程 2。

我在线程 1 中创建数据,然后 .lock,将数据推送到数组中,在线程 1 中使用 .unlock(),然后在线程 2 中读取此数据。当前在线程 2 中 I .lock();,循环数组显示用户数据,然后 .unlock();但这会导致我出现性能问题,因为线程 2 比线程 1 快,因此会导致渲染出现一些延迟。从线程 2 中删除 .lock 和 unlock 使我的滞后问题消失,我想知道这是否会导致任何问题?

【问题讨论】:

  • 你在使用 std::mutex 吗?如果是这样,用 std::scoped_lock<:mutex> 或 std::unique_lock<:mutex> 锁定。像这样:std::scoped_lock&lt;std::mutex&gt; lock{mtx};。锁需要尽可能短,你会遇到“没有免费的午餐”的问题。线程同步需要时间,您需要在设计中考虑到这一点。
  • 我正在使用 std::mutex PlayerData;确切地说,然后我填充了一个巨大的数组,不幸的是,这需要时间,因为有很多数据需要填充
  • 如果你从线程 2 中移除锁和解锁,那么你将没有线程同步,你可能会在线程 2 中渲染损坏的数据,因为不能保证数据在一个阅读时的一致状态。
  • 不锁定两个线程可能会导致一个线程看不到一致的数据状态。如果两个线程都必须持有锁来完成大部分工作,那么您最终只会得到多线程的缺点,而不是它的好处。您可以通过使用 2 个数据副本并锁定互斥锁仅用于交换线程副本来解决此问题,例如std::vector&lt;Data&gt;data; ...expensive computations ... { std::lock_guard lock(mutex); renderThreadData.swap(data); /* &lt;-- inexpensive operation */ }你甚至可以使用std::atomic来解锁...
  • minimal reproducible example 将有助于说明您的问题

标签: c++ multithreading mutex


【解决方案1】:

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

#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秒。

【讨论】:

    猜你喜欢
    • 2018-05-23
    • 2010-11-22
    • 1970-01-01
    • 2021-12-23
    • 2012-12-25
    • 1970-01-01
    • 2015-09-26
    • 2019-01-15
    相关资源
    最近更新 更多