Thử viết code lập trình đa luồng bằng TwinBasic và khả năng ứng dụng vào COM add-in chạy trong Excel

Liên hệ QC
Tôi tuân thủ nội quy khi đăng bài

nguyendang95

Thành viên chính thức
Tham gia
25/5/22
Bài viết
88
Được thích
83
TwinBasic, chắc nhiều đã từng nghe nói đến, là ngôn ngữ lập trình được nhiều tín đồ VB đánh giá là ứng viên rất sáng giá thay thế cho VB6/VBA hiện nay. Mặc dù qua nhiều năm vẫn còn đang ở giai đoạn beta, tuy nhiên TwinBasic tương thích khá tốt với VB6/VBA giúp lập trình viên có thể dễ dàng chuyển đổi, ngoài ra nó còn bổ sung thêm nhiều tính năng đáng giá mà VB6/VBA còn thiếu.
Nói về khả năng lập trình đa luồng, hiện tại TwinBasic vẫn chưa có cú pháp giúp lập trình viên dễ dàng triển khai tính năng này và tác giả của ngôn ngữ lập trình này cũng hứa hẹn bổ sung cú pháp trong Quý 2 năm nay theo như ghi nhận trong Roadmap (lịch trình) đăng tải trên Github của tác giả, tuy nhiên với sự trợ giúp của các hàm Win32 API, chúng ta có thể dễ dàng viết một ứng dụng chạy đa luồng và tốn chút sức lực để gỡ lỗi và chạy thử hoàn thiện.
Code dưới đây lần lượt tạo thread, gửi http request đến các URL trong danh sách và nhận lại phản hồi từ các URL này.

Mã:
Module MainModule
    Private Declare PtrSafe Function CreateThread Lib "Kernel32.dll" (ByVal lpThreadAttributes As LongPtr, ByVal dwStackSize As Long, ByVal lpStartAddress As LongPtr, ByVal lpParameter As LongPtr, ByVal dwCreationFlags As Long, ByRef lpThreadId As Long) As LongPtr
    Private Declare PtrSafe Function CloseHandle Lib "Kernel32.dll" (ByVal hObject As LongPtr) As Long
    Private Declare PtrSafe Function WaitForSingleObject Lib "Kernel32.dll" (ByVal hHandle As LongPtr, ByVal dwMiliseconds As Long) As Long
    Private Declare PtrSafe Sub CoUninitialize Lib "Ole32.dll" ()
    Private Declare PtrSafe Function CreateMutex Lib "Kernel32.dll" Alias "CreateMutexW" (ByVal lpMutexAttributes As LongPtr, ByVal bInitialOwner As Long, ByVal lpName As String) As LongPtr
    Private Declare PtrSafe Function ReleaseMutex Lib "Kernel32.dll" (ByVal hMutex As LongPtr) As Long
    Private Declare PtrSafe Function CoInitializeEx Lib "ole32.dll" (ByVal pvReserved As LongPtr, ByVal dwCoInit As Long) As Long
    Private Declare PtrSafe Function GetCurrentThreadId Lib "Kernel32.dll" () As Long
    Private Mutex As LongPtr
    Private Const COINIT_MULTITHREADED = &H0
    Private Const COINIT_DISABLE_OLE1DDE = &H4
    Private Const WAIT_OBJECT_0 = &H0
    Private Const INFINITE = -1&
    Private Const WAIT_ABANDONED = &H80
    Private HttpResponses As New Collection(Of String)
    Public Sub Main()
        Mutex = CreateMutex(0, 0, vbNullString) 'Khởi tạo Mutex để sử dụng cho mục đích đồng bộ giữa các thread
        If Mutex = 0 Then
            Console.WriteLine("Failed to create mutex")
            Exit Sub
        Else: Console.WriteLine("Mutex has been created")
        End If
        Dim Thread As LongPtr, ThreadId As Long, i As Long
        Dim Urls As Variant = Array("https://google.com.vn", "https://youtube.com", "https://x.com", "https://facebook.com")
        Dim Threads(0 To 3) As LongPtr
        For i = LBound(Urls) To UBound(Urls)
            Thread = CreateThread(0, 0, AddressOf GetHttpResponse, VarPtr(Urls(i)), 0, ThreadId) 'Tạo thread
            If Thread = 0 Then
                Console.WriteLine("Failed to create thread")
                CloseHandle(Mutex)
                Exit Sub
            End If
            Threads(i) = Thread
        Next
        For i = LBound(Threads) To UBound(Threads)
            WaitForSingleObject(Threads(i), INFINITE) 'Chờ các thread chạy xong
            CloseHandle(Threads(i)) 'Dọn dẹp thread
        Next
        CloseHandle(Mutex) 'Dọn dẹp Mutex sau khi dùng xong
        Console.WriteLine("Mutex has been destroyed")
        Console.WriteLine("Number of responses: " & CStr(HttpResponses.Count)) 'Số lượng http response tiếp nhận từ các thread
    End Sub
   
    Private Sub GetHttpResponse(ByVal Url As Variant)
        Dim ThreadId As Long = GetCurrentThreadId(), WaitResult As Long
        Console.WriteLine("Thread Id: " & CStr(ThreadId))
        'Khởi tạo COM library là MTA, thêm tùy chọn tắt tính năng OLE1DDE đã lỗi thời
        CoInitializeEx(0, COINIT_MULTITHREADED Or COINIT_DISABLE_OLE1DDE)
        Dim objWinHttp As WinHttp.WinHttpRequest
        Set objWinHttp = New WinHttp.WinHttpRequest
        With objWinHttp
            .Open("GET", Url, False)
            On Error Resume Next
            .Send()
            If Err.Number <> 0 Then
                Console.WriteLine("An error occurred. " & Err.Description)
            Else
                If .Status = 200 Then
                    Console.WriteLine("Response from " & Url & " with status code " & CStr(.Status))
                    WaitResult = WaitForSingleObject(Mutex, INFINITE) 'Thread tiến hành chiếm dụng Mutex
                    If WaitResult = WAIT_OBJECT_0 Then
                        Console.WriteLine("Mutex acquired by thread id " & CStr(ThreadId))
                        HttpResponses.Add(.ResponseText) 'Mục đích chiếm dụng Mutex là nhằm buộc các thread khác phải chờ đến lượt để ghi vào biến collection
                        'Tránh trường hợp các thread cùng ghi vào biến collection gây sai lệch kết quả, hay còn gọi là race condition
                        'Dùng xong Mutex thì hoàn trả để các thread khác sử dụng
                        If ReleaseMutex(Mutex) <> 0 Then
                            Console.WriteLine("Mutex released by thread id " & CStr(ThreadId))
                        Else: Console.WriteLine("An error occurred while trying to release mutex from thread id " & CStr(ThreadId))
                        End If
                    ElseIf WaitResult = WAIT_ABANDONED Then Console.WriteLine(CStr(ThreadId) & " acquired an abandoned mutex")
                    End If
                End If
            End If
            On Error GoTo 0
        End With
        CoUninitialize() 'Kết thúc sử dụng COM library
    End Sub
End Module

Kết quả trả về đúng như mong muốn.

1738665327346.png

Liên hệ đến khả năng lập trình đa luồng khi viết COM add-in cho Excel bằng TwinBasic
TwinBasic cho phép lập trình viên viết COM add-in cho các ứng dụng Office nói chung và Excel nói riêng. Như vậy lập trình viên có thể viết code đa luồng xử lý giúp cải thiện hiệu năng tính toán cho add-in, ví dụ như trích xuất dữ liệu từ các bảng tính sau đó tạo nhiều luồng xử lý tính toán và ghi kết quả ngược lại vào bảng tính, hoặc tạo một thread mới và đưa công việc tính toán nặng nề lên đó xử lý giúp UI của Excel không bị đơ, chẳng hạn.
Với mô hình đối tượng của Excel nói riêng và các ứng dụng Office nói chung, việc này có thể hơi phức tạp do nó luôn chạy trong thread chính STA. Tham khảo bài viết từ Microsoft Threading support in Office để biết thêm thông tin chi tiết.
 
Web KT

Bài viết mới nhất

Back
Top Bottom