Multithreading 我应该如何使用临界截面?

Multithreading 我应该如何使用临界截面?,multithreading,delphi,Multithreading,Delphi,我不知道应该把CriticalSection放在哪里。在线程中,我有一个公共过程(write),在这个过程中我将数据写入文件 调用此过程时,我应该在该过程中使用CriticalSection还是在每个线程中使用CriticalSection 例如: 我有一个线程,我创建了CS type TMyThread = class(TThread) private { Private declarations } CS:TCriticalSection; public pr

我不知道应该把CriticalSection放在哪里。在线程中,我有一个公共过程(write),在这个过程中我将数据写入文件

调用此过程时,我应该在该过程中使用CriticalSection还是在每个线程中使用CriticalSection

例如:

我有一个线程,我创建了CS

type
  TMyThread = class(TThread)
  private
    { Private declarations }
  CS:TCriticalSection;
  public
    procedure Write(msg:string);
  protected
    procedure Execute; override;
    constructor Create;
  end;


constructor TMyThread.Create;
begin
CS.TCriticalSection.Create;
end;
还有我的问题。在哪里使用CS

在那里:

procedure TMyThread.Write(msg:string);
begin
  CS.Enter;
  { WRITING IN FILE msg }
  CS.Leave;
end;
还是每一条线

CS.Enter;
MyThread.Write('cos');
CS.Leave;

这个答案是在假设每个线程都写入一个公共文件的基础上编写的。因此需要同步。如果,正如您在评论中提到的,每个线程都写入不同的文件,那么就不需要同步


您的代码有很多问题。您需要在关键部分的实例和受保护对象之间进行一对一映射。在这里,每个线程有一个关键部分,根本没有任何用途。您的代码不会执行任何序列化

由于您要保护对单个文件的访问,因此需要具有critical section对象的单个实例。每个线程都必须能够访问单个共享的临界截面对象。一些选择:

  • 将critical section对象传递给线程,并安排线程的使用者管理critical section对象的生存期
  • 在声明线程的单元的实现部分中,将critical section对象声明为全局变量。在单元的初始化和终结部分创建并销毁对象
  • 将临界截面对象声明为线程中的类变量。在类构造函数和类析构函数中创建和销毁对象
  • 将关键部分和日志写入移到专用日志类中
  • 除此之外,线程的构造函数被破坏。为了正确创建线程对象,必须调用继承的构造函数


    考虑到所有这些更改,您建议的使用关键部分的任何选项都将正常工作。但是,在
    Write
    中获取锁显然要好得多。这样,在不获取锁的情况下调用函数是不可能的。获取锁的代码只需编写一次。

    如果要从多个线程写入单个文件,则应在所有这些线程之间共享同一个临界段,这意味着您通常应在其他位置创建临界段实例,并将其传递给线程构造函数,例如

    type
      TMyThread = class(TThread)
      private
        { Private declarations }
        FCS:TCriticalSection;
      public
        procedure Write(msg:string);
      protected
        procedure Execute; override;
        constructor Create(ACS: TCriticalSection);
      end;
    
    constructor TMyThread.Create(ACS: TCriticalSection);
    begin
      inherited Create;  // don't forget to call inherited constructor
      FCS:= ACS;
    end;
    
    procedure TMyThread.Write(msg:string);
    begin
      FCS.Enter;
      { WRITING IN FILE msg }
      FCS.Leave;
    end;
    

    所以我只能在我写的这个过程中使用CS,任何其他线程都可以使用这个过程,一切都会好起来吗?我这样问是因为其他线程不会看到这个CS。其他线程确实看到了它。线程执行代码,当这些线程调用函数时,它们可以看到该部分。@MBo你是对的,代码还有许多其他问题。我没有仔细研究它。我会更新的,所以。。。我可以创建全局数组并为每个线程放置每个CS吗?不可以。假设每个线程都写入同一个文件,那么每个线程都需要恰好共享一个关键部分。如果每个线程都写入不同的文件,那么根本不需要同步;关键部分同步不同的线程实例,不清楚您将如何使用关键部分。所以我问如何使用关键部分:)您甚至使用谷歌了吗?重要的是要理解关键部分是为了保护数据(而不是代码)。您需要清楚地了解代码在做什么,以便知道多个线程何时可能访问共享数据。(数据可以在内存中,也可以在文件中;两种方式的主体都是相同的。)如果相同的代码总是从不同的线程访问不同的对象,则不需要关键部分。如果不同的代码从单个线程访问相同的对象,您仍然不需要关键部分。您只需要为使用相同对象/数据的多个线程使用它们。当您确实需要关键部分时,每个需要保护的对象必须由单个关键部分保护(否则根本没有保护)。此外,在开始使用来自任何可以访问数据的地方的数据之前,您需要确保输入关键数据。然而,在这一点上,理解保护数据和代码之间的区别是很重要的。您可以在实际接触数据的方法内部本地化输入critical,因为
    CS.Enter
    只是代码!这非常重要,避免了大量的重复代码。如果每个线程都有自己的文件和其他线程,除了在他的文件中写入之外,还想在其他“线程文件”中写入吗?这就是我想要实现的,您需要一种机制来为每个线程中的每个文件选择正确的关键部分。(如果我理解正确的话)可能是
    synchronize
    TCriticalSection