Reentrant và Thread-safe
TIL
720
Linux
99
White

BeanRedArmy viết ngày 29/03/2019

Reentrant và Thread-safe

Một chương trình máy tính, một hàm A hoặc một chương trình con được gọi là reentrant nếu nó có thể bị ngắt lúc đang thực thi bởi một hàm B và có thể được gọi lại (re-enter) khi hàm B kết thúc việc thực thi mà không làm sai lệch kết quả gốc khi hàm A thực hiện liền mạch. Việc ngắt có thể được gây ra bởi yếu tố bên trong (lập lịch hoặc call), hoặc bởi yếu tố bên ngoài ( như interrupt hoặc signal). Khi lần gọi sau (reentered invocation) hoàn tất, lần gọi trước đó (previous invocation) sẽ được phục hồi việc thực thi.
Một chương trình, hàm được gọi là thread-safe nếu nó chỉ kiểm soát những data dùng chung sao cho việc thực thi multithread phải đảm bảo an toàn ở cùng thời điểm, nghĩa là sẽ không xảy ra tranh chấp dữ liệu giữa những thread.

Một hàm reentrant có thể đạt được thread-safety, tuy nhiên ở một số tình huống, chỉ reentrant là không đủ để thread-safe. Ngược lại, một code thread-safe cũng chưa chắc đã reentrant. Ta xét ví dụ sau để thấy rõ.
Ví dụ này đơn giản chi là hàm swap() bằng code C.
1.. Không reentrant và Không thread-safe

int t;

void swap(int* x, int* y)
{
    t = *x;
    *x = *y;
    *y = t;    /* Hardware interrupt might invoke isr() here. */
}

void isr()
{
    int x = 1, y = 2;
    swap(&x, &y);
}
...
int a = 3, b = 4;
...
swap(&a, &b);
  • Hàm swap() này không thread-safe vì nó sử dụng biến t là non-const global. Như vậy các thread sẽ sử dụng chung biến t này và xảy ra tương tranh dữ liệu.
  • Hàm này không reentrant vì: alt text

2.. Có reentrant nhưng không thread-safe:

int t;

void swap(int* x, int* y)
{
    /* Save global variable. */
    int s;
    s = t;

    t = *x;
    *x = *y;
    *y = t;     /* Hardware interrupt might invoke isr() here. */

    /* Restore global variable. */
    t = s;
}

void isr()
{
    int x = 1, y = 2;
    swap(&x, &y);
}
...
int a = 3, b = 4;
...
swap(&a, &b);
  • Hàm này không thread-safe vì nếu ta chạy hai hàm swap(a,b) và swap(c,d) ở hai thread với a = 1, b = 2, c = 3, d = 4: alt text
  • Hàm này reentrant vì: alt text

Như vậy ta thấy quả thực rằng một hàm reentrant không phải luôn thread-safe. Thế một hàm thead-safe có phải luôn reentrant? Câu trả lời là không nốt. Ví dụ xét hàm thread-safe sau:

int f() {
    lock();
    // protected code
    unlock();
 }

Hàm trên hiển nhiên là không reentrant. Nếu nó đang đi vào lock mà bị ngắt để gọi lại từ đầu, nó sẽ không thể đi vào vùng protected code nữa, và luôn bị dừng lại ở đó, gây ra deadlock.

Ta sẽ viết lại hàm này để chúng thread-safe:

3.. Không reentrant nhưng lại thead-safe

_Thread_local int tmp;

void swap(int* x, int* y)
{
    tmp = *x;
    *x = *y;
    *y = tmp;    /* Hardware interrupt might invoke isr() here. */
}

void isr()
{
    int x = 1, y = 2;
    swap(&x, &y);
}

Việc sử dụng một biến thread local sẽ ngăn việc tương tranh tài nguyên giữa các thread.
Biến thread local là biến mà mỗi thread sẽ có riêng cho chúng một bản copy.

4.. Vừa reentrant vừa thread-safe

void swap(int* x, int* y)
{
    int tmp;
    tmp = *x;
    *x = *y;
    *y = tmp;    /* Hardware interrupt might invoke isr() here. */
}

void isr()
{
    int x = 1, y = 2;
    swap(&x, &y);
}

Việc cấp phát biến tmp trên stack của hàm sẽ làm cho hàm swap() vừa reentrant vừa thread-safe.

Ta có các quy tắc khi viết một hàm re-entrant:

  • Không sử dụng biến static và global trong hàm vì chúng có thể bị thay đổi bởi chính hàm đó, ảnh hưởng tới việc phục hồi thực thi.
  • Hàm không được chỉnh sửa code của chính nó. (ví dụ một số hàm graphic ở mức low level có khả năng generate ra chính nó)
  • Hàm không được gọi một hàm không reentrant khác.

Trong lập trình, ta luôn muốn chương trình đạt cả re-entrant và thread-safe.

BeanRedArmy 15-10-2018

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

BeanRedArmy

11 bài viết.
23 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
7 2
Device Tree trong Linux Device Tree (DT) là một file mô tả phần cứng, có kiểu định dạng giống JSON, nó mô tả một cấu trúc cây, ở đó thì các device...
BeanRedArmy viết 9 tháng trước
7 2
White
4 0
Context trong Linux Process context, interrupt context, user(space) context, system call context, atomic context, nonatomic context,... là những k...
BeanRedArmy viết 11 tháng trước
4 0
White
4 0
Tổng quan về giao tiếp liên tiến trình Interprocess communication (IPC) 1. Phân loại các công cụ giao tiếp tiến trình (Ảnh) Ta có thể chia các c...
BeanRedArmy viết 10 tháng trước
4 0
Bài viết liên quan
White
0 4
fCC: Technical Documentation Page note So I have finished the HTML part of this exercise and I want to come here to lament about the lengthy HTML ...
HungHayHo viết 1 năm trước
0 4
White
1 0
sudo du sh
t viết hơn 3 năm trước
1 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
11 bài viết.
23 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!