0

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

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

因此,此页面指出,如果有两个线程访问相同的数据,事情会变得很糟糕。解决方案是只允许一个线程同时访问数据。

这很清楚,我理解解决方案,只是为什么有人需要线程来执行此操作?重点是什么?如果线程被阻塞,只有一个线程可以执行,为什么还要使用它们呢?没有优势。(或者这只是一个愚蠢的例子;在这种情况下,请指点我一个明智的例子)

提前致谢。

4

5 回答 5

1

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

于 2013-07-11T05:49:54.153 回答
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功能仍然同时发生。信号量仅在线程需要修改某些共享(全局)状态或使用某些共享资源时发挥作用。因此,只有当另一个线程试图同时访问共享的东西时,一个线程才会阻塞。

现在,如果您的线程正在做的唯一一件事是使用一个共享变量/资源,那么您是对的——拥有线程根本没有意义(由于上下文切换,它实际上比一个线程效率低.)

于 2013-07-11T05:50:59.597 回答
1

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

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

于 2013-07-11T05:52:33.360 回答
0

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

于 2013-07-11T05:50:51.237 回答
0

琐碎示例的问题....

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

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

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

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

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

当然,只有当每个线程处理数据所花费的时间超过等待信号量所花费的时间时,它才是值得的。这限制了将代码拆分为线程产生好处的程度。超越这一点往往意味着整体执行实际上是连续的。

完全可以在没有信号量的情况下进行多线程编程。有 Actor 模型或 Communicating Sequential Processes(我喜欢的一个)。在 Wikipedia 上查找 JCSP 非常值得。

在这些编程风格中,数据通过将其发送到通信通道而在线程之间共享。因此,与其使用信号量来授予另一个线程对数据的访问权限,不如将数据的副本发送到类似于网络套接字或管道的东西上。CSP(它将通信通道限制为仅在接收者已读取时才发送完成)的优点是它可以防止您陷入困扰多线程执行程序的许多陷阱。听起来效率低下(复制数据效率低下),但实际上使用 Intel 的 QPI 架构、AMD 的 Hypertransport 并没有那么糟糕。这意味着“通道”真的可以是网络连接;设计内置的可扩展性。

于 2013-07-11T06:27:51.330 回答