thắc mắc Hỏi về multithreading

haylachoi

Senior Member
Thread.jpg


Từ kết quả trong hình thì có thể thấy, biến i và u có giá trị bị lặp lại, còn biến d thì ko bị lặp lại.
Có ai giải thích hộ mình tại sao lại có kết quả như trên ko?
Các giá trị của i và u bị lặp lại thì mình biết do có thread khác thay đổi các giá trị này, còn về biến d ko bị lặp lại, mình chỉ đoán là biến d sau mỗi lần lặp sẽ bị giải phóng nên thread nào muốn lấy giá trị của d thì phải lấy trước khi nhảy sang lần lặp tiếp, tuy nhiên lại ko đoán dc vì sao tại thời điểm đoạn lệnh "int d= i" chuẩn bị chạy, ko có thread nào khác thay đổi biến i.

PS: Mình bị nhầm đoạn thread khác thay đổi giá trị i. Việc thay đổi giá trị của các biến chỉ do main thread làm. Các giá trị khác nhau là vì thời điểm truy cập vào bộ nhớ để lấy giá trị đó thì đã giá trị đã bị đổi, d ko đổi vì d có vùng nhớ riêng.
 
Last edited:
View attachment 282285

Từ kết quả trong hình thì có thể thấy, biến i và u có giá trị bị lặp lại, còn biến d thì ko bị lặp lại.
Có ai giải thích hộ mình tại sao lại có kết quả như trên ko?
Các giá trị của i và u bị lặp lại thì mình biết do có thread khác thay đổi các giá trị này, còn về biến d ko bị lặp lại, mình chỉ đoán là biến d sau mỗi lần lặp sẽ bị giải phóng nên thread nào muốn lấy giá trị của d thì phải lấy trước khi nhảy sang lần lặp tiếp, tuy nhiên lại ko đoán dc vì sao tại thời điểm đoạn lệnh "int d= i" chuẩn bị chạy, ko có thread nào khác thay đổi biến i.
đơn giản như vầy
thread 1 là phần ngoài vòng lặp for hay còn gọi là main thread
thread 2 là phần trong vòng lặp for new thread()
thread 1 luôn chạy nhanh hơn thread 2 vì thread 1 là main thread và thread 2 thì tốn thời gian để khởi tạo bằng toán tử new


biến u khai báo ở ngoài và được gán bằng i
=> thread 1 thì u = i và đến cuối thì i = 20 nên dừng lặp for => i =20, u = 19

tiếp thread 2
biến d luôn bằng i khi ở trong vòng lặp => tới cuối d = 19

2 phần thread 1 và thread 2 tách biệt chạy như vậy đó
 
Cái này giải thích đơn giản mà, khi dùng Thread with ThreadStart (ko có parameterized) thì:
1. Thread Start() ko có nghĩa là việc thực thi sẽ thực hiện ngay -> Nghĩa là Console.WriteLine() ko được gọi ngay tức thời, màn hình hiển thị chỉ được render khi CPU quay tới nó. Nên nhớ Console là Theard Safety nghĩa là bạn có N lệnh WriteLine in Parallel thì cũng chỉ tuần tự được ghi ra.
2. int mỗi khi khai báo đều sinh ra một vùng stack memory riêng -> từ đó ta thấy u, i là 2 biến ko sinh ra vùng nhớ thêm mỗi khi gọi Console.WriteLine(). d mỗi lần loop lại được cấp 1 vùng stack mới nên nó sẽ khác nhau với mỗi lần gọi Console.WriteLine(). Vì thế d lúc nào cũng sẽ là một khoảng từ 0 -> 20 và ko lặp lại trong bất kỳ lệnh Thread.Start() nào.
3. Vì là bạn đang gọi start 20-threads nên đoạn string được write ra ngẫu nhiên, và tùy vào giá trị u i lúc đó sẽ được write ra, u và i có thể trùng hoặc ko trùng. Còn d tuy nhìn thấy có vẻ được gán nhưng 20 cái d đó là 20 vùng stack memory khác nhau.
(1) + (2) + (3) => Kết quả cho ra màn hình lộn xộn u,i nhưng d thì chỉ trong khoảng 0 -> 20 và ko lặp.
 
Last edited:
Cái này giải thích đơn giản mà, khi dùng Thread with ThreadStart (ko có parameterized) thì:
1. Thread Start() ko có nghĩa là việc thực thi sẽ thực hiện ngay -> Nghĩa là Console.WriteLine() ko được gọi ngay tức thời, màn hình hiển thị chỉ được render khi CPU quay tới nó. Nên nhớ Console là Theard Safety nghĩa là bạn có N lệnh WriteLine in Parallel thì cũng chỉ tuần tự được ghi ra.
2. int mỗi khi khai báo đều sinh ra một vùng stack memory riêng -> từ đó ta thấy u, i là 2 biến ko sinh ra vùng nhớ thêm mỗi khi gọi Console.WriteLine(). d mỗi lần loop lại được cấp 1 vùng stack mới nên nó sẽ khác nhau với mỗi lần gọi Console.WriteLine(). Vì thế d lúc nào cũng sẽ là một khoảng từ 0 -> 20 và ko lặp lại trong bất kỳ lệnh Thread.Start() nào.
3. Vì là bạn đang gọi start 20-threads nên đoạn string được write ra ngẫu nhiên, và tùy vào giá trị u i lúc đó sẽ được write ra, u và i có thể trùng hoặc ko trùng. Còn d tuy nhìn thấy có vẻ được gán nhưng 20 cái d đó là 20 vùng stack memory khác nhau.
(1) + (2) + (3) => Kết quả cho ra màn hình lộn xộn u,i nhưng d thì chỉ trong khoảng 0 -> 20 và ko lặp.

Cái vùng địa chỉ của biến d. Lúc đầu mình nghĩ là nó sẽ luôn giống nhau giữa các lần lặp cơ. Vì nghĩ là khi mỗi lần lặp kết thúc thì vùng stack đó sẽ bị thu lại, ở lần lặp tiếp sẽ lại cấp phát, và nó sẽ lại giống như lần trước.
Sau khi bác bảo là địa chỉ của d dc cấp mới, mình kiểm tra lại thì đúng là nó khác nhau thật, hơi lạ là các địa chỉ sau lớn hơn địa chỉ trước.

Nếu ko sử dụng biến d trong cái lambda expression truyền vào thread thì địa chỉ của biến d này không đổi qua mỗi lần lặp.
 
Last edited:
Cái vùng địa chỉ của biến d. Lúc đầu mình nghĩ là nó sẽ luôn giống nhau giữa các lần lặp cơ. Vì nghĩ là khi mỗi lần lặp kết thúc thì vùng stack đó sẽ bị thu lại, ở lần lặp tiếp sẽ lại cấp phát, và nó sẽ lại giống như lần trước.
Sau khi bác bảo là địa chỉ của d dc cấp mới, mình kiểm tra lại thì đúng là nó khác nhau thật, hơi lạ là các địa chỉ sau lớn hơn địa chỉ trước.

Nếu ko sử dụng biến d trong cái lambda expression truyền vào thread thì địa chỉ của biến d này không đổi qua mỗi lần lặp.

Về nguyên tắc đọc nhìn thì sau khi for thì stack memory phải được thu, nhưng đó là khi int d ko có liên kết nào nữa. Vì bạn đã khai báo sử dụng d trong delegate method của Thread nên vùng nhớ sẽ ko bị thu lại cho tới khi cái Thread đó vô trạng thái Complete.

MSDN của GC có viết rõ khi nào thì thu hồi memory:

It determines which objects are no longer being used by examining the application's [I]roots[/I]. An application's roots include static fields, local variables on a thread's stack, CPU registers, GC handles, and the finalize queue.

Tiếp theo là nguyên tắc sử dụng Stack Value, bất kỳ Stack Value nào đều được allocate memory khi khai báo tường minh như sau:

int a; // Mặc định là 0
double a; // Mặc định là 0.0f
bool a; // Mặc định là false
int a = 10; // Giá trị là 10
int b = a; // Thêm một giá trị 10 nữa, a != b về mặc memory allocation trong Stack
 
Back
Top