在 Windows 上,我们可以在同一个线程上多次调用 MyThread.waitfor。如果线程已经终止,没问题,这不会引发任何异常并立即返回(正常行为)。
在 Android 上,它是不同的,如果我们调用两次 MyThread.waitfor 那么我们将在第二次尝试时出现“没有这样的进程”的异常。
function TThread.WaitFor: LongWord;
{$ELSEIF Defined(POSIX)}
var
X: Pointer;
ID: pthread_t;
begin
if FExternalThread then
raise EThread.CreateRes(@SThreadExternalWait);
ID := pthread_t(FThreadID);
if CurrentThread.ThreadID = MainThreadID then
while not FFinished do
CheckSynchronize(1000);
FThreadID := 0;
X := @Result;
CheckThreadError(pthread_join(ID, X));
end;
{$ENDIF POSIX}
发生错误是因为在调用 waitfor 时他们设置了 FThreadID := 0 所以当然任何进一步的调用都会失败
我认为它必须这样写:
function TThread.WaitFor: LongWord;
{$ELSEIF Defined(POSIX)}
begin
if FThreadID = 0 then exit;
...
end;
{$ENDIF POSIX}
你怎么看?我需要在 emb 上打开错误请求吗?
最佳答案
pthread_join 的文档说:
Joining with a thread that has previously been joined results in undefined behavior.
这解释了为什么 TThread 采取措施避免调用未定义的行为。
设计有缺陷吗?这是有争议的。如果我们要考虑这个类的设计,让我们扩大讨论范围,就像设计师必须做的那样。一个 Windows 线程可以被多个不同的线程等待。 pthread 不是这种情况。链接的文档还说:
If multiple threads simultaneously try to join with the same thread, the results are undefined.
所以我认为 Embarcadero 无法合理地在 Posix 平台上实现 Windows 上已经存在的相同行为。正如您所描述的,可以肯定的是,他们可以对同一线程进行特殊情况的重复等待。好吧,他们必须保留线程返回值,以便 WaitFor 可以返回它。但这只会让你走到那一步,而且无论如何都不会很有用。毕竟,您为什么要从同一个线程再次等待?
我怀疑 FThreadID 设置为 0 是为了避免未定义的行为并以更稳健的方式失败。但是,如果多个线程调用 WaitFor,则会出现数据竞争,因此仍可能出现未定义的行为。
如果我们想做慈善,那么我们可以
将这些具体细节放在一边,很明显,如果 WaitFor 是通过调用 pthread_join 实现的,那么跨平台的不同行为是不可避免的。 Embarcadero 已尝试为每个平台调整 TThread 实现,但它们不能完全等效,因为平台功能不同。 Windows 提供了一组比 pthreads 更丰富的线程原语。
如果 Embarcadero 选择了一条不同的道路,他们可以完美地对齐平台,但需要在 Posix 上更加努力地工作。可以在那里复制 Windows 行为,但必须使用 pthread_join 以外的其他方法来实现此特定方法。
尽管面对现实,我认为您将不得不适应 pthread 的不同功能。在 pthreads 中,等待线程的能力只是为了方便。如果您真的想支持重复等待,您最好等待事件或条件变量。另一方面,您可能只是重新创建代码以确保您只等待一次。
因此,总而言之,如果还没有问题,您应该向 Embarcadero 提出问题。他们可能会考虑支持您的方案。在系统中出现问题是值得的。但是,如果他们选择什么都不做并证明这是因为无法克服的更广泛的平台差异,并且类中需要额外的复杂性来支持您有些毫无意义的用例,请不要感到惊讶。我希望我们都同意的一件事是 TThread.WaitFor 的 Delphi 文档应该涵盖这些问题。
关于android - 这是android下TThread的bug吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40665972/
这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我在OSX上(如果重要的话)。如果我使用RVM安装Ruby,它会默认将Bundler安装到@globalgemset假设我想要一个不同版本的bundler。我假设我需要做的就是执行geminstallbundler--version但是,这会将bundler安装到默认gemset并且RVM不会为其设置路径。因此,如果我键入bundler,它仍会启动一个与Ruby一起安装到@global中的bundler两个问题:如何将bundler安装到@globalgemset。将bundler安装到@globalgemset中的模式是否正确,或者我遗漏了什么 最佳答案
在ruby.h中,有很多函数宏是这样定义的:staticinlineint#ifdefined(HAVE_PROTOTYPES)rb_type(VALUEobj)#elserb_type(obj)VALUEobj;#endif{if(FIXNUM_P(obj))returnT_FIXNUM;if(obj==Qnil)returnT_NIL;if(obj==Qfalse)returnT_FALSE;if(obj==Qtrue)returnT_TRUE;if(obj==Qundef)returnT_UNDEF;if(SYMBOL_P(obj))returnT_SYMBOL;returnBU
fruit=["apple","red","banana","yellow"]=>["apple","red","banana","yellow"]Hash[*fruit]=>{"apple"=>"red","banana"=>"yellow"}为什么splat会导致数组被如此整齐地解析为Hash?或者更准确地说,Hash如何“知道”“apple”是键,“red”是其对应的值?仅仅是因为它们在水果数组中的位置是连续的吗?这里使用splat有关系吗?否则哈希不能直接从数组中定义自己吗? 最佳答案 作为documentation状态:H
我是Ruby的新手,我正在制作一个gem来与JSONRPCAPI交互,基本上所有调用和响应都非常相似,每个API调用都可以用一个函数处理,例如:Module::api_command('APINamespace.NamespaceMethod')但我也想(为了方便起见)能够做到:Module::APINamespace.NamespaceMethod是否有任何理由不通过使用Module.const_missing返回一个具有method_missing的虚拟类来执行此操作,这将允许将调用从Module::APINamespace.NamespaceMethod传递到Module::ap
这个问题在这里已经有了答案:Isitpossibletohaveclass.property=xreturnsomethingotherthanx?(3个答案)关闭8年前。我想迭代一个字符串数组,并将它们中的每一个分配给类User的一个新实例,我希望我会得到一个User对象数组:classUserdefname=(name)@name=nameselfendendoriginal_array=["aaa","bbb","bbb"]result=original_array.collect{|str|User.new.name=str}但结果是一个字符串数组!putsresult.ins
我遇到了Ryanbates在他的authlogicRailscast中使用的称为record的方法,但似乎无法理解它的作用。我已经阅读了文档,但我似乎无法理解该帮助器的用途。defcurrent_userreturn@current_userifdefined?(@current_user)current_user_session&¤t_user_session.recordend我想知道的是,这是否只是从数据库中获取记录,以及为什么它与从数据库中获取数据的标准方式不同。谢谢。 最佳答案 这个“记录”方法是UserSes
'required'))%>'fullwidth'%>为什么会产生以下错误?$erb-x-T-test.erb|ruby-c-:3:syntaxerror,unexpected')'...form.field_container:namedo).to_s);_erbout.concat"\n"...^-:9:syntaxerror,unexpected$end,expecting')' 最佳答案 如果您查看erb-x-T-test.erb输出的代码:#coding:ASCII-8BIT_erbout='';_erbout.conca
在SOquestion2068165一个答案提出了使用这样的东西的想法:params[:task][:completed_at]&&=Time.parse(params[:task][:completed_at])作为DRYer的说法params[:task][:completed_at]=Time.parse(params[:task][:completed_at])ifparams[:task][:completed_at]paramsHash将来自(Rails/ActionView)表单。这是众所周知的||=习语的一种推论,如果LHS不是nil/false则设置值。像这样使用&&