多线程中哪些变量需要同步

WinSockCF 2010-09-01 05:36:39
1.在 TThread类的private,protected,public中建立的变量,在线程执行中是否需要同步?

2.如果在Execute中建立了局部变量,想要这个局部变量每次都获取在程序创建时建立的全局变量Tstringlist

那么这块获取的代码需要同步吗?我感觉是读值,而不参与写的操作,应该不用同步吧?

获取的代码比如:
这里是窗体创建时建立的全局变量:SourceList:tstinglist;
此为线程创建的局部变量:Source:=SourceList[0];----这里获取值的时候,需要同步嘛?

3.在线程类中的变量都为副本,这句话对嘛?
...全文
325 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
WinSockCF 2010-09-02
  • 打赏
  • 举报
回复
5楼的朋友回答的真的特别好,我不知道他用了多久打的这么多字.
也不知道构思了多长时间,
让我不得不将全部分给他,再说声谢谢!也谢谢其它朋友了~呵
haitao 2010-09-01
  • 打赏
  • 举报
回复
楼上说的太好了

补充一个Tthreadlist,对于楼主可能有用
wxieyang 2010-09-01
  • 打赏
  • 举报
回复
就拿你给的例子来说吧,主线程(也就是包含主窗体的那个线程)中定义的那个TStringList变量,如果在子线程读取其内容的同时,主线程有可能更新其内容,则需要同步函数进行读,如果主线程不更改其内容,则不需要同步读取。
另外,你需要知道一件事情,
var
LS: TStringList
其中额LS仅仅是个指针,他指向在堆中实际的TStringList对象,因此,简单的将LS赋值给另一个变量,并不是将TStringList中的内容赋值过去了,仅仅是复制了一个指向同一个对象内存的指针而已。
如果需要将一个TStringList列中的内容赋值给另一个TStringList,则需要使用Assign函数
例如,将 ls1 赋值给 ls2 ,则

ls2.Assign(ls2)

同样,对字符串的赋值操作也需要小心,字符串属于生存期自管理的数据类型,如果你的程序确实需要得到某个字符串的副本,请使用copy 函数来实际复制这个字符串。这点在多线程中尤为重要。

好了,下面针对你上面提到的问题来简单回答一下。
TThread中,包含在private和protected中的数,因为只能在线程类内部进行访问,因此不需要同步。而public中的数据,是否需要同步,则视情况而定。如果其他的线程与本线程涉及到同时的读写访问,则需要同步,否则就不需要同步。

对于第二个问题,在Execute,如果涉及到访问主线程中的数据,原则上最好使用同步函数。
如果在你的读取访问时,能确保被读取的数据不会被主线程或者其他线程修改,则不需要使用同步函数


另外,从你2楼给的问题补充上,我觉得你对线程、线程类(TThread)以及线程函数 之间的关系还不太怎么清楚,下面就简单说下:
在winxp中,所有能执行的东西,都是在线程中完成的,进程被操作系统加载完成后,会创建一个线程,然后把执行权交给这个线程,这个线程就是主线程。在主线程中,用户可以创建任意多个线程来完成自己的工作。线程和线程之间,操作系统以一种看似并行的方式来让所有线程同时工作。
线程本身,仅仅是一个内核对象,用户create一个线程,实际上是创建了一个内核对象,在用户create一个线程的时候,会指定一个函数作为线程开始运行的起始位置,这个函数就是线程函数。操作系统在创建完了线程内核对象之后,就会跳转到用户给定的这个线程函数的开始处继续执行(当然,创建一个挂起的线程除外)。
多个线程,可以指向同一个线程函数,每个线程函数都会被操作系统在一个相对独立的环境中执行,彼此不会干扰(除非你的线程函数主动去访问其他线程的数据),就像同一个函数会被多个地方调用而不会被彼此干扰一样(这个比喻不太恰当,函数的调用时分时的,线程函数被操作系统加载可能是同时的,但是即使是同时,彼此也不会被干扰)。
线程函数内部定义的变量,都是在独立的栈中创建的,因此,不同线程即使使用同一个线程函数,因为彼此的栈不同,因此线程函数内部的变量时不同的。但是,如果线程内部变量主动去访问其他线程中的数据,则就可能涉及到线程同步问题。
比如楼主提到的要用线程函数内部的变量去访问主线程中的一个字符串,这时候,你就需要保证在你读数据的时候,数据不能被其他线程改写。通常这种保证最简单的方式是使用线程同步函数(Synchronize 的方式)对字符串进行copy工作(注意这里说的是使用copy函数进行字符串复制而不是简单的变量赋值)

好了,现在再说说TThread类,这个类是delphi对windows线程的一个包装,你可以简单的认为就是windows的线程,这个类中定义的数据,基本上都是要在线程内部使用的,虽然创建线程的时候,数据是在其他线程中开辟的内存空间,但是线程执行起来之后,线程类中的数据大部分时候还是在线程内部来使用,因此,一般情况下,访问TThread中的数据时不需要同步的。而Execute函数,你可以简单的理解为是线程函数。

针对第三个问题:
3.在线程类中的变量都为副本,这句话对嘛?
这句话不单单对线程类来说是正确的,对任何一个类来说都是正确的。
比如
var
ls1,ls2,ls3; TStringList;
如果你分别创建这三个列表,则每个列表对象都是对TStringList的一种复制。

可以这么理解,TStringList就是一个模具,通过Create创建出来的对象,就是用这个模具来生产产品一样。
不知道你小时候自己家做过鱼花馒头没有?做这个鱼花馒头,有一个鱼花模具,把面和好之后,放在鱼花模具中按一下,就出来一个鱼花,然后上笼屉蒸,熟了就是个鱼花馒头了,类就好比那个鱼花模具,馒头就好比实际创建出来的对象了。因此,每一个通过类创建的对象,都是类的一个个实体,他们彼此都是独立的。

类中的数据域,每个对象都是独立的,但是累中的方法(函数和过程),是唯一的,每一个类只有一份,所有的对象都是访问这一份方法的。
问什么大家都访问者一份方法却能互相不干扰呢?
这里就需要说线程和堆栈的问题了,每一个线程都会有一个独立的栈来保持一些特有的数据,比如函数中的变量等,进入某个函数,首先会在栈中留出在函数声明部分声明的那些变量所占据的位置用来保持变量的值,函数结束之后,这部分空间就会被收回,下次再进入这个函数,又会被预留,函数结束的时候又会被收回,周而复始。
栈的规则是后进先出,就像有一个出口的一条线的停车场一样,先开进来的汽车停最里面,后开进来的汽车停在靠外的地方,出去的时候,需要先把后进来的汽车开出去,先进来的汽车才能出去。栈就是这么个数据结构。结合着我上面说的内容,那就是,后被调用的函数,其函数内部的变量会被保存到栈的最上面,函数结束的时候,变量被清理出去,然后就回到了调用者的函数变量层,如此反复,确保了每个调用都能正确地回到自己正确的环境中。一个线程默认情况下,只有一个栈,因为在线程中的所有代码都是顺次执行的,因此通过栈就能保证函数内部的变量的正确性。
每个线程都会有不同的栈,因此,即使在不同的线程中同时执行一个函数,因为不处在一个栈中,所有函数内部预留的空间是在不同的栈中,不会互相影响。
wxieyang 2010-09-01
  • 打赏
  • 举报
回复
线程类中定义的变量,如果仅仅在本线程中访问,则不需要同步,如果和其他线程交互,如果只涉及到读,也不需要同步,如果涉及到多个线程读写,则需要同步
WinSockCF 2010-09-01
  • 打赏
  • 举报
回复
急等答案咯!希望高手朋友,能够进来说两句
WinSockCF 2010-09-01
  • 打赏
  • 举报
回复
呵,可能楼上朋友没明白我的意思
我的意思就是同时创建多个线程,例如
MyThread:array[0..2] of TThread;
同时创建三个线程,来运行线程类内的Execute!
根据这个问题?在来解答我上边提问的问题~~~
  • 打赏
  • 举报
回复
两个线程都会使用的变量。
其他不需要同步

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧