信号量&线程 - 有什么意义?

时间:2013-07-11 05:43:44

标签: multithreading semaphore

我一直在阅读有关信号量的信息并且看到了这篇文章:

www.csc.villanova.edu/~mdamian/threads/posixsem.html

所以,这个页面说明如果有两个线程访问相同的数据,事情会变得很丑陋。解决方案是只允许一个线程同时访问数据。

这很清楚,我理解解决方案,只有为什么有人需要线程才能做到这一点?有什么意义?如果线程被阻止以便只有一个可以执行,为什么要使用它们呢?没有优势。 (或者这可能只是一个愚蠢的例子;在这种情况下,请指出一个合理的例子)

提前致谢。

5 个答案:

答案 0 :(得分:1)

当您使用多线程时,并非每个运行的代码都会被阻塞。例如,如果你有一个队列,并且两个线程正在从该队列中读取,那么你将确保没有线程同时从队列中读取,因此该部分将被阻塞,但这部分可能会占用更短的时间。从队列中检索要处理的项目后,所有其余代码都可以异步运行。

答案 1 :(得分:1)

考虑一下:

void update_shared_variable() {
    sem_wait( &g_shared_variable_mutex );

    g_shared_variable++;

    sem_post( &g_shared_variable_mutex );
}

void thread1() {

    do_thing_1a();
    do_thing_1b();
    do_thing_1c();

    update_shared_variable();   // may block
}

void thread2() {

    do_thing_2a();
    do_thing_2b();
    do_thing_2c();

    update_shared_variable();   // may block
}

请注意,所有do_thing_xx功能仍然会同时发生。当线程需要修改某些共享(全局)状态或使用某些共享资源时,信号量才会发挥作用。所以一个线程只会阻止另一个线程同时尝试访问共享的东西。

现在,如果您的线程正在进行的事情正在使用一个共享变量/资源,那么您是正确的 - 根本没有线程(它实际上会更少)由于上下文切换,效率高于一个线程。)

答案 2 :(得分:1)

线程背后的想法是允许同时处理。必须管理共享资源以避免死锁或饥饿等问题。如果某些事情需要一段时间才能处理,那么为什么不创建这些流程的多个实例以使它们更快完成?当进程必须等待I / O时,瓶颈就是你提到的。

与处理时间相比,在等待共享资源时被阻塞的情况很小,这是您想要使用多个线程的时候。

答案 3 :(得分:0)

这当然是一个SSCCE(简短,自包含,正确的例子) 假设您有2个工作线程可以完成大量工作并将结果写入文件。 您只需要锁定文件(共享资源)访问权限。

答案 4 :(得分:0)

琐碎的例子的问题......

如果您尝试解决的问题可以分解为可以并行执行的部分,那么线程是一件好事。

一个稍微不那么简单的例子 - 想象一个for循环,每次迭代中处理的数据每次都不同。在这种情况下,您可以在单独的线程中同时执行for循环的每次迭代。事实上,像英特尔这样的一些编译器会自动将适合于循环的编译器转换为线程。在这种特殊情况下,由于迭代的数据独立性,不需要信号量。

但是说你想要处理一个数据流,并且该处理有两个不同的步骤,A和B.无线程方法将涉及读取一些数据然后执行A然后B然后在读取更多输入之前输出数据。或者你可以让一个线程读取并执行A,另一个线程执行B和输出。那么如何从第一个线程到第二个线程获得中间结果?

一种方法是使用内存缓冲区来包含中间结果。第一个线程可以将临时结果写入内存缓冲区,第二个线程可以从中读取。但是由于两个线程独立运行,第一个线程无法知道是否可以安全地覆盖该缓冲区,并且第二个线程无法知道何时从中读取它。

这是您可以使用信号量来同步两个线程的操作的地方。第一个线程接受一个信号量,我将其称为 empty ,填充缓冲区,然后发布一个名为 filled 的信号量。同时第二个线程将获取已填充的信号量,读取缓冲区,然后发送 empty 。只要已填充初始化为0并且初始化为1,它就会起作用。第二个线程只在第一个线程写入数据后处理数据,第一个线程在第二个线程完成之前不会写入数据。

当然,如果每个线程处理数据所花费的时间超过等待信号量所花费的时间,那么它是值得的。这限制了将代码分割成线程产生益处的程度。超越这意味着整体执行是有效的。

可以完成没有信号量的多线程编程。有演员模型或沟通顺序进程(我赞成的那个)。在维基百科上查找JCSP非常值得。

在这些编程风格中,数据通过向下发送通信通道在线程之间共享。因此,不是使用信号量来授予另一个线程访问数据的权限,而是将数据的副本发送到有点像网络套接字或管道的地方。 CSP的优势(它限制了通信通道只发送 - 只有接收器已经读取)才能阻止你陷入困扰多线程程序的许多陷阱。这听起来效率低下(复制数据效率低下),但实际上英特尔的QPI架构,AMD的Hypertransport并没有那么糟糕。这意味着'通道'实际上可能是一个网络连接;设计内置的可扩展性。