2010-10-27 34 views
8

Tôi đã xem GCC docs để xác định macro và có vẻ như những gì tôi muốn là không thể, nhưng tôi đoán nếu có, ai đó ở đây sẽ biết.Có thể xác định macro giống chức năng với một thân biến?

Những gì tôi muốn làm là xác định macro này:

synchronized(x) { 
    do_thing(); 
} 

nào mở rộng để:

{ 
    pthread_mutex_lock(&x); 
    do_thing(); 
    pthread_mutex_unlock(&x); 
} 

Trong C++ Tôi chỉ có thể làm cho một đối tượng SynchronizedBlock mà được các khóa trong constructor và mở khóa của nó trong destructor, nhưng tôi không có ý tưởng làm thế nào để làm điều đó trong C.

Tôi nhận ra tôi có thể sử dụng một con trỏ hàm trong biểu mẫu synchronized(x, &myfunction);, nhưng của tôi mục đích là làm cho một số mã C trông giống Java nhiều nhất có thể. Và vâng, tôi biết đây là điều ác.

+4

Bạn thực sự nên suy nghĩ kỹ trước khi cố gắng làm cho một ngôn ngữ trông giống như ngôn ngữ khác. Một macro trông giống như cú pháp bạn đang yêu cầu sẽ vô cùng khó hiểu đối với người đọc nó dưới dạng C. –

+0

R. đúng là điều này có thể khiến mọi thứ trở nên khó đọc, vì không dễ dàng thấy được rằng đây là một macro. Tôi nghĩ điều tốt nhất là tuân thủ quy ước rằng các macro phải là chữ hoa và tên đó phải thực sự mang tính thông tin. Tôi sẽ đi cho một cái gì đó như 'MUTUALY_EXCLUDE' hoặc như vậy. –

+0

^'Và có, tôi biết đây là điều ác. ' –

Trả lời

16

EDIT: Đã thay đổi thành phiên bản của nategoose

#define synchronized(lock) \ 
for (pthread_mutex_t * i_#lock = &lock; i_#lock; \ 
    i_#lock = NULL, pthread_mutex_unlock(i_#lock)) \ 
    for (pthread_mutex_lock(i_#lock); i_#lock; i_#lock = NULL) 

Và bạn có thể sử dụng nó như này:

synchronized(x) { 
    do_thing(x); 
} 

Hoặc thậm chí không có dấu ngoặc

synchronized(x) 
    do_thing(); 
+0

Rất ấn tượng. Ngay cả những con số dòng trong các lỗi sẽ đi ra ngay. Lỗi thực sự duy nhất là đối số khóa không nên xuất hiện hai lần trong macro và bạn đã thoát khỏi hầu hết dấu vết của bạn '\\' s – nategoose

+5

Điều đó đồng thời đáng kinh ngạc và đáng sợ. Tôi chưa bao giờ nghĩ về điều đó. –

+3

này cần khắc phục cả hai: '#define đồng bộ (khóa)' \ 'for (pthread_mutex_t * i_ = &lock; i_; i_ = NULL) '\ ' for (pthread_mutex_lock (i_); i_;' \ 'pthread_mutex_unlock (i_), i_ = NULL) ' – nategoose

4

Dưới đây là một sự khởi đầu, nhưng bạn có thể cần phải tinh chỉnh nó:

#define synchronized(lock, func, args...) do { \ 
    pthread_mutex_lock(&(lock)); \ 
    func(##args); \ 
    pthread_mutex_unlock(&(lock)); \ 
} while (0) 

Sử dụng như thế này (không may, không phải là cú pháp Java như bạn muốn):

synchronized(x, do_thing, arg1, arg2); 
+0

Có vẻ như' do ... while (0) 'là không cần thiết,' {..} 'hoạt động một mình (ít nhất với gcc). Điều này vẫn đòi hỏi một khối như 'đồng bộ (x, hàm)' thay vì 'đồng bộ (x) {/ * function * /}' mặc dù. –

+0

Nevermind, tôi thấy những gì 'do ... while (0)' là cho. –

+0

Đây là lý do cho việc làm/trong khi: http://kernelnewbies.org/FAQ/DoWhile0 – Jonathan

1

Đây là tốt nhất mà tôi đã đưa ra:

#define synchronized(x, things) \ 
     do { \ 
      pthread_mutex_t * _lp = &(x); \ 
      pthread_mutex_lock(_lp);  \ 
      (things);      \ 
      pthread_mutex_unlock(_lp); \ 
     } while (0) 

... 

     synchronized(x,(
          printf("hey buddy\n"), 
          a += b, 
          printf("bye buddy\n") 
         )); 

Lưu ý rằng bạn phải sử dụng toán tử dấu phẩy hiếm khi được sử dụng và có các hạn chế đối với mã nào có thể nằm trong danh sách mã đồng bộ hóa (không hoàn toàn giống như java).

2

Câu hỏi rất thú vị!

Tôi đã xem các câu trả lời khác và thích câu trả lời bằng cách sử dụng for. Tôi có một sự cải tiến, nếu tôi có thể! GCC 4.3 giới thiệu mẫu COUNTER mà chúng tôi có thể sử dụng để tạo các tên biến duy nhất.

#define CONCAT(X, Y) X##__##Y 
#define CONCATWRAP(X, Y) CONCAT(X, Y) 
#define UNIQUE_COUNTER(prefix) CONCATWRAP(prefix, __COUNTER__) 

#define DO_MUTEX(m, counter) char counter; \ 
for (counter = 1, lock(m); counter == 1; --counter, unlock(m)) 

#define mutex(m) DO_MUTEX(m, UNIQUE_COUNTER(m)) 

Sử dụng những macro, mã này ...

mutex(my_mutex) { 
    foo(); 
} 

... sẽ mở rộng để ...

char my_mutex__0; 
for (my_mutex__0 = 1, lock(my_mutex); my_mutex__0 == 1; --my_mutex__0, unlock(m)) { 
    foo(); 
} 

Với my_mutex__n bắt đầu từ 0 và tạo ra một tên mới mỗi thời gian sử dụng của nó! Bạn có thể sử dụng kỹ thuật tương tự để tạo các phần mã giống như màn hình, với một tên duy nhất nhưng không rõ cho mutex.

+0

Tôi thích cách tiếp cận này, nhưng nó không hoạt động nếu tôi vượt qua một thành viên cấu trúc. chronized (object-> lock) {/ * stuff * /} 'mở rộng thành' char object-> lock__0;/* etc */', gây ra vấn đề vì lock__0 không phải là thành viên cấu trúc. –

+0

Ahh, true = (tốt, câu trả lời sửa đổi ở trên trông tốt hơn, và không cần quầy.Chơi! – slezica

+0

Chỉ cần đặt biến '_lock_ ## __COUNTER__' có vẻ hoạt động (và giải quyết vấn đề trong việc triển khai khác). –

Các vấn đề liên quan