线程基础: |
- 线程操作包括线程的创建、终止、同步(连接、阻塞)、调度、数据管理和进程交互。
- 线程不维护已创建线程的列表,也不知道创建它的线程。
- 一个进程中的所有线程共享相同的地址空间。
- 同一进程中的线程共享:
- 进程说明
- 大多数数据
- 打开文件(描述符)
- 信号和信号捕捉程序
- 当前工作目录
- 用户和组 ID
- 每个线程都有一个独特的:
- 线程 ID
- 一组寄存器,堆栈指针
- 局部变量堆栈,返回地址
- 信号掩码
- 优先事项
- 返回值:errno
- 如果正常,pthread 函数将返回“0”。
program mutex_demo1;
{$IFDEF FPC}
{$MODE Delphi}//MacPas}
{$assertions on}
{$ENDIF}
{$APPTYPE CONSOLE}
{$R *.res}
{$DEFINE __PTW32_MUTEX_TYPES}
uses
{$IFnDEF FPC}
System.SysUtils,
System.Win.Crtl,
Winapi.Windows,
{$ELSE}
Sysutils,
{$ENDIF}
libc.Types in '..\libc.Types.pas',
pthreads.win in '..\pthreads.win.pas',
pthreads.sem in '..\pthreads.sem.pas',
pthreads.sched in '..\pthreads.sched.pas',
pthreads.barrier in '..\pthreads.barrier.pas',
pthreads.mutex in '..\pthreads.mutex.pas',
pthreads.mutexattr in '..\pthreads.mutexattr.pas',
pthreads.spin in '..\pthreads.spin.pas',
pthreads.attr in '..\pthreads.attr.pas',
pthreads.cond in '..\pthreads.cond.pas',
pthreads.condattr in '..\pthreads.condattr.pas',
pthreads.rwlock in '..\pthreads.rwlock.pas',
pthreads.ptw32 in '..\pthreads.ptw32.pas',
pthreads.oldmutex in '..\pthreads.oldmutex.pas',
pthreads.core in '..\pthreads.core.pas',
pthreads.CPU in '..\pthreads.CPU.pas',
QueueUser_APCEx in '..\QueueUser_APCEx.pas';
procedure DoMessage(Message, Filename: String; LineNumber: Integer; ErrorAddr: Pointer);
var
S: String;
begin
S := Format('%s (%s, line %d, address $%x)',
[Message, Filename, LineNumber, Pred(Integer(ErrorAddr))]);
//OutputDebugString(PChar(S));
Writeln(S);
end;
procedure AssertErrorHandler(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
{ No local variables. Not compiler generated temporary variables. }
{ Using the call stack here will cause Access Violation errors. }
begin
DoMessage(Message, Filename, LineNumber, ErrorAddr);
//raise EMyAssert.Create('Boom!');
end;
var
mutex1 : pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;
counter : integer = 0;
function functionC(arg: Pointer): Pointer;
begin
pthread_mutex_lock( &mutex1 );
Inc(counter);
writeln(format('Counter value: %d',[counter]));
pthread_mutex_unlock( &mutex1 );
end;
procedure main;
var
rc1, rc2 : integer;
thread1, thread2 : pthread_t;
begin
{ Create independent threads each of which will execute functionC }
rc1 := pthread_create( &thread1, nil, &functionC, nil );
if rc1 > 0 then
begin
writeln(format('Thread creation failed: %d',[rc1]));
end;
rc2 := pthread_create( &thread2, nil, &functionC, nil );
if rc2 > 0 then
begin
writeln(format('Thread creation failed: %d',[rc2]));
end;
{ Wait till threads are complete before main continues. Unless we }
{ wait we run the risk of executing an exit which will terminate }
{ the process and all threads before the threads have completed. }
pthread_join( thread1, nil);
pthread_join( thread2, nil);
halt(0);
end;
begin
AssertErrorProc := AssertErrorHandler;
try
main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
线程同步: |
线程库提供了三种同步机制:
- mutexes - 互斥锁:阻止其他线程访问变量。这强制线程对变量或变量集的独占访问。
- joins - 让一个线程等到其他线程完成(终止)。
- condition 变量 - 数据类型pthread_cond_t
互斥锁:
互斥锁用于防止由于竞争条件导致的数据不一致。当两个或多个线程需要对同一内存区域执行操作时,通常会发生竞争条件,但计算结果取决于执行这些操作的顺序。互斥锁用于序列化共享资源。每当一个全局资源被多个线程访问时,该资源都应该有一个与之关联的互斥锁。可以应用互斥锁来保护一段内存(“关键区域”)免受其他线程的影响。互斥锁只能应用于单个进程中的线程,而不能像信号量那样在进程之间工作。
Without Mutex | With Mutex | ||
---|---|---|---|
int counter=0; /* Function C */ void functionC() { counter++ } | /* Note scope of variable and mutex are the same */ pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; int counter=0; /* Function C */ void functionC() { pthread_mutex_lock( &mutex1 ); counter++ pthread_mutex_unlock( &mutex1 ); } | ||
Possible execution sequence | |||
Thread 1 | Thread 2 | Thread 1 | Thread 2 |
counter = 0 | counter = 0 | counter = 0 | counter = 0 |
counter = 1 | counter = 1 | counter = 1 | Thread 2 locked out. Thread 1 has exclusive use of variable counter |
counter = 2 |
如果用于变量counter 递增的寄存器加载和存储操作 发生在不幸的时间,理论上可以让每个线程递增并用相同的值覆盖相同的变量。另一种可能性是Thread2会首先增加counter 锁定Thread1直到完成,然后Thread1将其增加到 2。
Sequence | Thread 1 | Thread 2 |
---|---|---|
1 | counter = 0 | counter=0 |
2 | Thread 1 locked out. Thread 2 has exclusive use of variable counter | counter = 1 |
3 | counter = 2 |
当一个mudex锁试图针对另一个线程所持有的mutex时,该线程将被阻塞,直到该mudex被解锁。当线程终止时,除非明确解锁,否则该mudex不会做什么。默认情况下什么都不会发生。