【问题标题】:C/Linux: Uses of thread synchronizationC/Linux:线程同步的使用
【发布时间】:2020-07-29 19:46:30
【问题描述】:

我很难理解线程同步。我得到了以下线程函数:

void *thread_function(void *unused)
{
    long aux;

    for(int i = 0; i < 1000; i++){
        aux = count;
        aux++;
        usleep(random() % 10);
        count = aux;

    }

    return NULL;
}

count 是一个全局变量,初始化为 0。如果我用 N 个线程(例如 4)运行此函数,count 会在值 1000 附近波动。

为什么会发生这种情况,正确的计数值应该是多少?如果我在 for 循环之前放置一个信号量 sem_wait,在 for 循环之后放置 sem_post,这是否意味着我的线程不再并行运行?我应该将sem_waitsem_post 放在哪里才能使我的线程正确同步?

【问题讨论】:

    标签: c linux multithreading synchronization


    【解决方案1】:

    您假设操作是原子的。现在假设它们不是,在实际系统中就是这种情况。

    作为一个全局变量,count 可以被系统中的所有线程访问。这意味着,在没有同步的情况下,所有线程将以非确定性和交错的方式执行以下操作:

    for(int i = 0; i < 1000; i++){
        aux = count;
        aux++;
        usleep(random() % 10);
        count = aux;
    
    }
    

    总而言之,在循环的每次迭代中,每个线程都会在给定的时刻拥有 count 值的副本,递增该副本 (aux++),然后将 count 分配给本地值 count = aux; .

    问题 1:每个线程读取的值 count 在线程执行时可能因线程而异,因为一个线程可能正在读取一个值,该值在紧接之后的某个时间瞬间被另一个(或多个)线程修改(请记住,操作不是原子的,可以以交错的方式执行)。

    问题 2:分配给 count 的值不受任何锁定机制的保护,这意味着多个线程可能以交错方式甚至同时执行该指令(例如,在多处理器系统中这是可能的) .这意味着正在执行的线程之一(您不知道它是什么)会将count = aux 中的count 的值设置为aux

    一个可能的执行场景的简单示例:

    例如,让我们假设三个线程。线程 1 读取值 count = 100 并被抢占。线程 2 读取值 100 并执行一段时间,将计数设置为(比如说)300,然后它被抢占。最后,线程 3 读取值 300 并执行一些循环迭代。如果线程 1 再次执行并设置值 count = aux,则在一次循环迭代后,值将设置为 101。看看问题!

    需要同步以确保只有一个线程在执行读取、递增和赋值,实际上是为了使操作表现得好像它们是原子的。


    问:如果我在 for 循环之前放置一个信号量 sem_wait,在 for 循环之后放置 sem_post,这是否意味着我的线程不再并行运行?

    答:这意味着每个线程将交错执行 for 循环。例如,线程 1 将执行 for 循环的 100 次迭代,线程 2 将执行 200 次迭代等。请记住:调度程序控制每个线程的执行,因此迭代次数不受用户控制。您的代码是同步的,但不是以理想的方式。


    问:我应该将sem_waitsem_post 放在哪里才能使我的线程正确同步?

    答:您应该将信号量用于尽可能少的需要同步的操作,以便从并发/并行代码执行中获得最大收益。例如,使用信号量,您的代码可能是:

    for(int i = 0; i < 1000; i++){
        sem_wait(...);
            count++;
        sem_post(...);
    }
    

    您不再需要aux,因为信号量确保只有一个线程在增加count 的值。

    注意,当您使用线程时,您也可以使用互斥锁代替信号量。

    我希望这能澄清你的疑虑。

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 2019-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      相关资源
      最近更新 更多