|
Multithreading
|
|
|
IXFile components support threading and can be safely used in multithreaded environment; some conditions must be observed,
however, to guarantee correct behaviour of objects. IXFile is designed to operate on one file and one thread at a time -
that is single instance of the class can be accessed by only one thread. In other words the same object should not be
shared between threads. Multiple instances of the class, however, can be safely accessed by multiple threads simultaneously
for concurrent execution. Object contains necessary synchronization code to protect shared resources; for performance reasons,
however, methods are not completely reentrant and allow concurrent execution on separate objects only. Object is not reusable in a strict sense
but it does not cause any inconvience in development of multithreaded applications as explained futher. First, we must answer the question
when multiple threads may need access to the same object. Perhaps the only situation is when multiple threads need access to the same file.
But this can be - and should be - accomplished with multiple object accessing the same file. In other words each thread should create
its own object, open the same file in appropriate sharing mode and access data. File locking should be probably used to protect data against corruption.
Unbufferred transfer can be also useful to avoid accessing data processed by other threads. Take a look at 'MultiLock' sample source code to see how this can be
done in practice. If you still must share the same object between threads, you can do this, but all operations on the object must be explicitly synchronized
to ensure that every IXFile method is executed in critical section.
COM component is built with 'Both' threading model and therefore can be used in both single- (STA) and multithreaded (MTA) apartments. If it is used in STA,
COM ensures that only one thread accesses the object at a time. Synchronization code is also called but it does not impair performance because
methods contain only minimal required synchronization code. If object is created in MTA then it has all neccessary synchronization code and can
be accessed by multiple threads. In both cases object is created in apartment that creates it, so no cross-apartment marshalling occurs.
Examples
C++
int main(int, char**)
{
HANDLE th1, th2, th3;
long ith1, ith2, ith3;
long rth1, rth2, rth3;
th1 = CreateThread(NULL, 0, ThreadProc, (void *)1, 0, &ith1);
th2 = CreateThread(NULL, 0, ThreadProc, (void *)2, 0, &ith2);
th3 = CreateThread(NULL, 0, ThreadProc, (void *)3, 0, &ith3);
.
.
.
do
{
Sleep(1000);
GetExitCodeThread(th1, &rth1);
if(rth1 == STILL_ACTIVE)
continue;
GetExitCodeThread(th2, &rth2);
if(rth2 == STILL_ACTIVE)
continue;
GetExitCodeThread(th1, &rth3);
if(rth3 == STILL_ACTIVE)
continue;
break;
}
.
.
.
return(0);
}
DWORD WINAPI ThreadProc(LPVOID mode)
{
IFile *ixf;
long data;
long lock;
long rc;
ixf = new IFile();
ixf->SetLicenseKey("YOURLICENSEKEY");
ixf->Initialize(IXF_MODE_RDWR_CLOSE);
ixf->OpenAdvanced("test.bin", IXF_FILE_RDWR, IXF_FILE_SHARE_RDWR, IXF_FILE_OPEN);
ixf->SetActiveBufferSize(0);
do
{
lock = ixf->LockLong(-1, 1, FALSE);
rc = ixf->GetLong(&data, 1);
if(rc > 0)
{
data += (long)mode;
ixf->PutLong(&data, 1);
}
ixf->Unlock(lock);
} while(rc > 0);
delete ixf;
.
.
.
return(0);
}
BASIC .NET
Sub Main()
Dim th1, th2, th3 As Threading.Thread
th1 = New Threading.Thread(AddressOf ThreadProc1)
th2 = New Threading.Thread(AddressOf ThreadProc2)
th3 = New Threading.Thread(AddressOf ThreadProc3)
th1.Start()
th3.Start()
th2.Start()
th1.Join()
th2.Join()
th3.Join()
.
.
.
End Sub
Sub ThreadProc1()
ThreadProc(1)
End Sub
Sub ThreadProc2()
ThreadProc(2)
End Sub
Sub ThreadProc3()
ThreadProc(3)
End Sub
Sub ThreadProc(ByVal mode As Integer)
Dim ixf As IXFLIB.IXFile
Dim data as Integer
Dim lock as Integer
Dim rc as Integer
ixf = New IXFLIB.IXFile
ixf.SetLicenseKey("YOURLICENSEKEY")
ixf.Initialize(IXF_MODE_RDWR)
ixf.OpenAdvanced("test.bin", IXFLIB.FileAccessMode.IXF_FILE_RDWR, IXFLIB.FileShareMode.IXF_FILE_SHARE_RDWR, IXFLIB.FileCreationDisposition.IXF_FILE_OPEN)
ixf.SetActiveBufferSize(0)
Do
lock = ixf.LockLong(-1, 1, False)
rc = ixf.GetLong(data, 1)
If rc > 0
data += mode
ixf.PutLong(data, 1)
End If
ixf.Unlock(lock)
Loop While rc > 0
ixf.Close()
.
.
.
End Sub