mutex & 조건변수

윤 상배

dreamyun@yahoo.co.kr



1절. 소개

그동안 Pthread_1, Pthread_2, Pthread_3, 을 통해서 pthread 에 대한 몇가지 기본적인 내용들에 대해서 알아 보았다.

그중 Pthread_3 에서 조건변수와, mutex 잠금에 대한 설명이 있었는데, 설명만 있었고 실질적인 예를 이용한 테스트는 없었다.

이번에는 mutex 잠금과 조건변수에 대한 이해를 도울수 있는 간단한 어플리케이션을 제작해보고 어떠한 문제점을 가질수 있는지에 대한 테스트도 하게 될것이다.


2절. Mutex 잠금과 조건변수 테스트

2.1절. 테스트용 어플리케이션 개요

테스트용 어플리케이션의 이름은 mutex_con.c 로 하도록 하겠다. 이 프로그램은 3개의 쓰레드로 이루어진다. 첫 번째 쓰레드는 main 쓰레드로 나머지 2개의 쓰레드(thread 1, thread 2) 를 생성하고 (pthread_create) join 하는 일을 하게 될것이다(즉 특별히 하는일 없다). 2번째 쓰레드는 2개의 int 형 멤버변수를 가지는 구조체에 접근해서 특정한 숫자를 입력하게 된다. 3번째 쓰레드는 이 구조체에 접근해서 멤버변수의 값을 읽어와서 "뎃셈" 하고 이를 화면에 출력시켜주는 일을한다.

이때 이 구조체는 2번 쓰레드와 3번쓰레드 모두가 접근하게 되므로 mutex 잠금을 이용해서 한번에 하나의 쓰레드만 접근하도록 제어해야 될것이다.

mutex 잠금을 이용한 접근제어 외에도, 3번째 쓰레드는 2번째 쓰레드에 의해서 구조체의 값이 변경되었다는걸 감지하고, 값이 변경된 시점에서 구조체에 접근해야 한다. 즉 구조체의 값이 변경될때까지 기다려야 한다. 이 "기다림" 을 위해서 조건변수를 사용하게 된다.

이 조건변수라는 것은 간단히 말해서 신호(signal)를 주고 받는 개념이다. 한쪽에서는 신호를 기다리다가, 신호가 오면 신호를 감지해서 필요한 일을 하게 되는 개념이다.


2.2절. 조건변수를 통해 얻는 프로그래밍 상의 이점

조건변수를 사용하지 않는 다면 어떻게 될까. (물론 조건변수 대신 세마포어를 사용할수도 있으나 이는 논외로 하자.) 그렇다면 thread 2 에서는 구조체의 정보가 변경되었는지 알수 없음으로 구조체의 정보가 변경되었는지 확인하기 위해서 busy wait(바쁜대기 상태)에 놓이면서 지속적으로 값이 변경되었는지를 확인해야 할것이다.

하지만 이건 좋은 방법이 아니다. busy wait 상태란 점도 맘에 들지 않지만 실제로 thread 1 에서 값을 변경했는데 기존의 값과 같을수도 있기 때문이다. 기존의 값과 같든지 아니든지 간에 thread 2 에서는 값을 읽어들여야 하는데, 값의 변경을 확인하는 방법으론 체크자체가 불가능해 질수가 있다.

위의 문제를 해결하기 위해서 별도의 변수를 하나더 둘수 있을것이다. 그래서 thread 1 에서 구조체의 값을 변경시켰다면 이 별도의 준비한 변수의 값을 변경하는 것이다. 그리고 thread 2 에서는 바쁜 대기 상태에서 이 변수의 값이 변경되었는지 확인해서 구조체의 값을 가져오는 것이다. 이 방법을 사용하면 위의 문제를 해결할수 있겠지만, 역시 바쁜 대기 상태에 놓이게 된다는 단점을 가지게 된다.

조건 변수를 사용하면 이러한 모든 문제를 해결할수 있다. 조건 변수를 사용하게 되면 thread 2 에서는 thread 1 에서 조건변수를 통해서 시그널을 보내기 전까지 대기 상태에 놓일수 있을것이기 때문이다.

조건변수는 메모리 buffer 처리등에 유용하게 사용될수 있을것이다. 조건변수를 사용함으로써, 만약에 메모리 buffer 에 처리해야될 자료가 없다면 busy wait 상태에 놓일 필요 없이 signal 을 기다리면 될것이기 때문이다. 그래서 signal 이 도착하면 메모리 buffer 에 엑세스를 시도해서 최근의 정보를 가져오면 될것이다. 이 외에도 조건변수는 쓰레드간 동기화등과 같은 다른 영역에도 매우 유용하게 사용할수 있다.


2.3절. 작동 프로세스

작동 프로세스는 어떻게 mutex 잠금과 조건변수를 이용해서 임계영역을 보호하고 구조체의 값의 변경시점을 알수 있는지에 대한 내용을 중심으로 해서 기술할것이다.

  thread 2  
  while (1) 
  {
      mutex 잠금을 얻는다. 
      // 임계영역 시작 ----------------------------------------------
      구조체에 접근해서 값을 가져온다.  
      구조체 멤버변수의 값을 변경한다.(2씩 더한다)
      pthrad_cond_signal 를 이용해서 조건변수를 통해 신호를 보낸다. 
      // 임계영역 끝 ------------------------------------------------
      mutex 잠금을 돌려준다.
	  sleep(1);
  } 

  thread 3
  while(1)
  {
      mutex 잠금을 얻는다. 
      // 임계영역 시작 ----------------------------------------------
      pthread_cond_wait 를 이용해서 조건변수를 통해 신호가 오는지 기다린다.   
      if (신호가 도착한다면)
          두개의 구조체 멤버변수의 값을 덧셈 하고 이를 출력한다. 
      // 임계영역 끝 ------------------------------------------------
      mutex 잠금을 돌려준다.
  }
			


2.4절. 코딩

이제 작동프로세스까지 만들어졌으니, 코딩에 들어가도록 한다. 코딩에 들어가기 위해서는 작동프로세스 외에도 설계서가 필요할것이지만, 이러한 경우 매우 간단한 프로그램으로 작동프로세스 자체가 설계서나 마찬가지임으로 설계서 이런건 생략하도록 하겠다.

예제 : mutex_con.c

#include <pthread.h>
#include <string.h>
#include <unistd.h>

pthread_mutex_t mutex_lock   = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t   thread_cond  = PTHREAD_COND_INITIALIZER;

struct com_data
{
    int a;
    int b;
};

struct com_data mydata;

void *do_write(void *data)
{
    mydata.a = 0;
    mydata.b = 0;
    while(1)
    {
        pthread_mutex_lock(&mutex_lock);
        mydata.a = random() % 6000;
        mydata.b = random() % 6000;
        pthread_cond_signal(&thread_cond);
        pthread_mutex_unlock(&mutex_lock);
        sleep(2);
    }
}

void *do_read(void *data)
{
    while(1)
    {
        pthread_mutex_lock(&mutex_lock);
        pthread_cond_wait(&thread_cond, &mutex_lock);
        printf("%4d + %4d = %4d\n", mydata.a, mydata.b, mydata.a + mydata.b); 
        pthread_mutex_unlock(&mutex_lock);
    }
}

int main()
{
    pthread_t p_thread[2];
    int thr_id;
    int status;
    int a = 1;
    int b = 2;

    thr_id = pthread_create(&p_thread[0], NULL, do_write, (void *)&a); 
    thr_id = pthread_create(&p_thread[1], NULL, do_read, (void *)&b);

    pthread_join(p_thread[0], (void **) status);
    pthread_join(p_thread[1], (void **) status);

    return 0;
}

			

프로그램자체는 매우 간단하지만 조건변수의 기본적인 사용방법을 알수 있을것이다.


2.5절. 조건변수 사용시 주의해야될 사항

조건변수에는 pthread_cond_signal 과 ptherad_cond_wait 를 이용해서 신호를 주고, 기다리는 방식을 사용한다고 했다. 그렇다면 생각할수 있는게, 과연 신호가 실시간으로 전달이 될것이란걸 믿을수 있을까?

실시간으로 전달되는지 아닌지가 중요한 이유는 쓰레드가 신호를 보내고 나서 신호를 잘받았는지 기다리지 않고 바로 다음으로 넘어가 버리기 때문이다.

이건 꽤 중요한 문제가 될수도 있다. 왜냐하면 만약 신호가 실시간으로 전달되지 않는다면 신호가 미쳐 전달되기 전에 어떤 데이타가 변경되어 버리는 경우가 발생할수 있기 때문이다.

            쓰레드 공유변수 A = 0

 thread 1                                    thread 2
 while(1)                                    while(1)
 {                                           {
     쓰레드 공유변수 A++      
     신호 보냄           ------------------>     신호  기다림
  }                                           } 
                                           
			
위의 상황을 생각해 보자 최초 공유변수 A 에 0 이 들어간다. thread 1 에서 여기에 1 을 증가시키고 신호를 보낸다. thread 2 는 신호를 받고 A 의 값을 읽어 들여서 이것을 100 으로 나눈다. 그런데 신호가 늦게 보내져서 - thread 1 의 loop 회전속도가 신호를 보내는 시간보다 빠른경우 - thread 2 에서 신호를 미쳐 받기전에 A ++ 이 한번더 실행되고 A 의 값은 2가 될것이다. 이때 서야 thread 2 로 신호가 전달되었다면 결국 thread 1 에서는 2번의 데이타를 보냈는데 thread 1 는 한번의 연산만 실행한것으로 데이타 하나를 잃어 버린것과 같은 문제가 발생해 버린다.

신호는 매우 빠른 시간에 전달됨으로 보통의 경우 신호전달시간을 염두에 두어야 하는 경우는 발생하지 않을것이다. 하지만 불행하게도 염두에 두어야 하는 경우가 발생하기도 한다.

물론 우리 프로그래머들의 사전에 불가능이란 없으므로 위의 문제도 간단하게 해결가능 하다. 조건변수를 2개 쓰면 된다. thread 1 에서 신호를 보냈다면, thread 1 은 다음 루틴으로 넘어가기 전에 thread 2 에서 넘어오는 신호를 기다리도록 하면 될것이다. thread 2 는 thread 1의 신호를 받은뒤 thread 1으로 신호를 보내게 될것임으로 반드시 신호가 전달될것을 확신할수 있을것이다. 2개의 조건변수를 지원하기 위해서 2개의 mutex 잠금이 필요할것이다. 여기에서는 그 구현까지 설명하지는 않을것이다. 조금만 생각해보면 간단하게 구현 가능할것이기 때문이다.

 thread 1                                    thread 2
 while(1)                                    while(1)
 {                                           {
     쓰레드 공유변수 A++      
     신호 1 보냄           ----------------->     신호 1 기다림
	 신호 2 기다림         <----------------      신호 2 보냄
     ....                                            ....
 }                                           } 
  			

신호의 전달에 걸리는 시간은 운영체제에 따라 상당한 차이를 보인다. 그러므로 이러한 오차시간까지도 염두에 두어야할 상황이 발생한다면 시간테스트를 해야할것이다.

Posted by 김용환 '김용환'

댓글을 달아 주세요

jtable tutorial

java UI 2005. 2. 16. 12:02

 

http://java.sun.com/docs/books/tutorial/uiswing/components/table.html

 

The JavaTM Tutorial

Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Trail: Creating a GUI with JFC/Swing
Lesson: Using Swing Components

How to Use Tables

With the JTable (in the API reference documentation) class you can display tables of data, optionally allowing the user to edit the data. JTable doesn't contain or cache data; it's simply a view of your data. Here's a picture of a typical table displayed within a scroll pane:

A snapshot of TableDemo, which displays a typical table.

[PENDING: Update this snapshot.
Label these parts:
- each cell displays an item of data
- each column header describes its column
maybe also have these labels: 
- each column contains one type of data
- a table header displays the column headers]

The rest of this section tells you how to accomplish some common table-related tasks. Here are the topics this section covers:

Creating a Simple Table

A snapshot of SimpleTableDemo, which displays a simple table.

[PENDING: This figure will be updated.]

Try this: 
  1. Run SimpleTableDemo using JavaTM Web Start (in the Creating a GUI with JFC/Swing trail). Or, to compile and run the example yourself, consult the example index.
  2. Click the cell that contains "Snowboarding".
    The entire first row is selected, indicating that you have selected Mary Campione's data. A special highlight indicates that the "Snowboarding" cell is editable. Generally, you begin editing a text cell by double-clicking it.
  3. Position the cursor over "First Name". Now press the mouse button and drag to the right.
    As you can see, users can rearrange columns in tables.
  4. Position the cursor just to the right of a column header. Now press the mouse button and drag to the right or left.
    The column changes size, and the other columns adjust to fill the remaining space.
  5. Resize the window containing the table so that it's bigger than necessary to display the whole table.
    All the table cells become wider, expanding to fill the extra horizontal space.

Here is the code that implements the table in SimpleTableDemo.java (in a .java source file):
String[] columnNames = {"First Name",
                        "Last Name",
                        "Sport",
                        "# of Years",
                        "Vegetarian"};

Object[][] data = {
    {"Mary", "Campione",
     "Snowboarding", new Integer(5), new Boolean(false)},
    {"Alison", "Huml",
     "Rowing", new Integer(3), new Boolean(true)},
    {"Kathy", "Walrath",
     "Knitting", new Integer(2), new Boolean(false)},
    {"Sharon", "Zakhour",
     "Speed reading", new Integer(20), new Boolean(true)},
    {"Philip", "Milne",
     "Pool", new Integer(10), new Boolean(false)}
};

JTable table = new JTable(data, columnNames);
The SimpleTableDemo example uses one of two JTable constructors that directly accept data:
  • JTable(Object[][] rowData, Object[] columnNames)
  • JTable(Vector rowData, Vector columnNames)
The advantage of these constructors is that they're easy to use. However, these constructors also have disadvantages:
  • They automatically make every cell editable.
  • They treat all data types the same (as strings). For example, if a table column has Boolean data, the table can display the data in a check box. However, if you use one of the two JTable constructors listed previously, your Boolean data will be displayed as a string. You can see this difference in the last column of the two previous pictures of tables.
  • They require that you put all of the table's data in an array or vector, which isn't appropriate for some data. For example, if you're instantiating a set of objects from a database, you might want to query the objects directly for their values, rather than copying all their values into an array or vector.
If you want to get around these restrictions, you need to implement your own table model, as described in Creating a Table Model.

Adding a Table to a Container

It's easy to put a table in a scroll pane. You need just one or two lines of code:
JScrollPane scrollPane = new JScrollPane(table);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
The scroll pane automatically gets the table's header, which displays the column names, and puts it on top of the table. Even when the user scrolls down, the column names remain visible at the top of the viewing area. The scroll pane also tries to make its viewing area the same as the table's preferred viewing size. The previous code snippet sets the table's preferred viewing size with the setPreferredScrollableViewportSize method.

If you're using a table without a scroll pane, then you must get the table header component and place it yourself. For example:

container.setLayout(new BorderLayout());
container.add(table.getTableHeader(), BorderLayout.PAGE_START);
container.add(table, BorderLayout.CENTER);

Setting and Changing Column Widths

By default, all columns in a table start out with equal width, and the columns automatically fill the entire width of the table. When the table becomes wider or narrower (which might happen when the user resizes the window containing the table), all the column widths change appropriately.

When the user resizes a column by dragging its right border, then either other columns must change size, or the table's size must change. By default, the table's size remains the same, and all columns to the right of the drag point resize to accommodate space added to or removed from the column to the left of the drag point.

The following figures illustrate the default resizing behavior. [PENDING: These will be updated.]

SimpleTableDemo
Initially, the columns have equal width.

SimpleTableDemo during resizing
When the user resizes a column, some of the other columns must adjust size for the table to stay the same size.

SimpleTableDemo after the entire table is resized
When the entire table is resized, all the columns are resized.

To customize initial column widths, you can invoke setPreferredWidth on each of your table's columns. This sets both the preferred widths of the columns and their approximate relative widths. For example, adding the following code to SimpleTableDemo makes its third column bigger than the other columns:

TableColumn column = null;
for (int i = 0; i < 5; i++) {
    column = table.getColumnModel().getColumn(i);
    if (i == 2) {
        column.setPreferredWidth(100); //sport column is bigger
    } else {
        column.setPreferredWidth(50);
    }
}

As the preceding code shows, each column in a table is represented by a TableColumn (in the API reference documentation) object. TableColumn supplies getter and setter methods for the minimum, preferred, and maximum widths of a column, as well as a method for getting the current width. For an example of setting cell widths based on the actual amount of space needed to draw the cells' contents, see the initColumnSizes method in TableRenderDemo.java (in a .java source file).

When the user explicitly resizes columns, the columns' preferred widths are set such that the user-specified sizes become the columns' new current widths. However, when table itself is resized — typically because the window has resized — the columns' preferred widths do not change. Instead, the existing preferred widths are used to calculate new column widths to fill the available space.

You can change a table's resize behavior by invoking the setAutoResizeMode method. The method's argument should have one of these values (defined as constants in JTable):

AUTO_RESIZE_SUBSEQUENT_COLUMNS
The default. In addition to resizing the column to the left of the drag point, adjusts the sizes of all columns to the right of the drag point.
AUTO_RESIZE_NEXT_COLUMN
Adjusts only the columns immediately to the left and right of the drag point.
AUTO_RESIZE_OFF
Adjusts the table size instead.

Detecting User Selections

The following code snippet shows how to detect when the user selects a table row. By default, a table allows the user to select multiple rows — not columns or individual cells — and the selected rows need not be next to each other. Using the setSelectionMode method, the following code specifies that only one row at a time can be selected.
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
...
//Ask to be notified of selection changes.
ListSelectionModel rowSM = table.getSelectionModel();
rowSM.addListSelectionListener(new ListSelectionListener() {
    public void valueChanged(ListSelectionEvent e) {
        //Ignore extra messages.
        if (e.getValueIsAdjusting()) return;

        ListSelectionModel lsm =
            (ListSelectionModel)e.getSource();
        if (lsm.isSelectionEmpty()) {
            ...//no rows are selected
        } else {
            int selectedRow = lsm.getMinSelectionIndex();
            ...//selectedRow is selected
        }
    }
});
The code is from SimpleTableSelectionDemo.java (in a .java source file). SimpleTableSelectionDemo also has code (not included in the preceding snippet) that changes the table's selection orientation. By changing a couple of boolean values, you can make the table allow either column selections or individual cell selections, instead of row selections.

For more information and examples of implementing selection, see How to Write a List Selection Listener.

Creating a Table Model

As the following figure shows, every table gets its data from an object that implements the TableModel (in the API reference documentation) interface.

TableDemo

[PENDING: This figure might be updated to look more modern.]

The JTable constructor used by SimpleTableDemo creates its table model with code like this:

new AbstractTableModel() {
    public String getColumnName(int col) {
        return columnNames[col].toString();
    }
    public int getRowCount() { return rowData.length; }
    public int getColumnCount() { return columnNames.length; }
    public Object getValueAt(int row, int col) {
        return rowData[row][col];
    }
    public boolean isCellEditable(int row, int col)
        { return true; }
    public void setValueAt(Object value, int row, int col) {
        rowData[row][col] = value;
        fireTableCellUpdated(row, col);
    }
}
As the preceding code shows, implementing a table model can be simple. Generally, you implement your table model in a subclass of the AbstractTableModel (in the API reference documentation) class.

Your model might hold its data in an array, vector, or hash map, or it might get the data from an outside source such as a database. It might even generate the data at execution time.

Here again is a picture of a table implemented by TableDemo (which you can run using Java Web Start (in the Creating a GUI with JFC/Swing trail)) that has a custom table model:

A snapshot of TableDemo. Again.

[PENDING: This figure will be updated.]

This table is different from the SimpleTableDemo table in the following ways:

  • TableDemo's custom table model, even though it's simple, can easily determine the data's type, helping the JTable display the data in the best format. SimpleTableDemo's automatically created table model, on the other hand, isn't smart enough to know that the # of Years column contains numbers (which should generally be right aligned and have a particular format). It also doesn't know that the Vegetarian column contains boolean values, which can be represented by check boxes.
  • In TableDemo, we implemented the custom table model so that it doesn't let you edit the name columns; it does, however, let you edit the other columns. In SimpleTableDemo, all cells are editable.

Below is the code from TableDemo.java (in a .java source file) that is different from the code in SimpleTableDemo.java (in a .java source file). Bold font indicates the code that makes this table's model different from the table model defined automatically for SimpleTableDemo.

public TableDemo() {
    ...
    JTable table = new JTable(new MyTableModel());
    ...
}

class MyTableModel extends AbstractTableModel {
    private String[] columnNames = ...//same as before...
    private Object[][] data = ...//same as before...

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return data.length;
    }

    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

    /*
     * Don't need to implement this method unless your table's
     * editable.
     */
    public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        if (col < 2) {
            return false;
        } else {
            return true;
        }
    }

    /*
     * Don't need to implement this method unless your table's
     * data can change.
     */
    public void setValueAt(Object value, int row, int col) {
        data[row][col] = value;
        fireTableCellUpdated(row, col);
    }
    ...
}

Detecting Data Changes

A table and its model automatically detect whenever the user edits the table's data. However, if the data changes for another reason, you must take special steps to notify the table and its model of the data change. Also, if you don't implement a table model, as in SimpleTableDemo, then you must take special steps to find out when the user edits the table's data.

An example of updating a table's data without directly editing it is in the BINGO application. The BINGO application, which is presented in BINGO! (in the Creating a GUI with JFC/Swing trail), has a table that displays some information about each user who is signed up to play the game. When a new user signs up to play BINGO, the table needs to add a new row for that user. More precisely, the table model needs to get the data for the new user, and then the table model needs to tell the table to display the new data.

To notify the table model about a new user, the BINGO application invokes the table model's updatePlayer method. You can see the code for that method in PlayerInfoModel (in a .java source file), which contains the implementation of the table model. The updatePlayer method records the new user's data and fires a table-model event. Because every table listens for table-model events from its model, the user-information table automatically detects the change and displays the new data.

To fire the table-model event, the model invokes the fireTableRowsInserted method, which is defined by the AbstractTableModel class. Other fireXxxx methods that AbstractTableModel defines are fireTableCellUpdated, fireTableChanged, fireTableDataChanged, fireTableRowsDeleted, fireTableRowsInserted, fireTableRowsUpdated, and fireTableStructureChanged.

If you have a class such as SimpleTableDemo that isn't a table or table model, but needs to react to changes in a table model, then you need to do something special to find out when the user edits the table's data. Specifically, you need to register a TableModelListener (in the API reference documentation) on the table model. Adding the bold code in the following snippet makes SimpleTableDemo react to table data changes.

import javax.swing.event.*;
import javax.swing.table.TableModel;

public class SimpleTableDemo ... implements TableModelListener {
    ...
    public SimpleTableDemo() {
        ...
        table.getModel().addTableModelListener(this);
        ...
    }

    public void tableChanged(TableModelEvent e) {
        int row = e.getFirstRow();
        int column = e.getColumn();
        TableModel model = (TableModel)e.getSource();
        String columnName = model.getColumnName(column);
        Object data = model.getValueAt(row, column);

        ...// Do something with the data...
    }
    ...
}

Concepts: Editors and Renderers

Before you go on to the next few tasks, you need to understand how tables draw their cells. You might expect each cell in a table to be a component. However, for performance reasons, Swing tables aren't implemented that way.

Instead, a single cell renderer is generally used to draw all of the cells that contain the same type of data. You can think of the renderer as a configurable ink stamp that the table uses to stamp appropriately formatted data onto each cell. When the user starts to edit a cell's data, a cell editor takes over the cell, controlling the cell's editing behavior.

For example, each cell in the # of Years column in TableDemo contains Number data — specifically, an Integer object. By default, the cell renderer for a Number-containing column uses a single JLabel instance to draw the appropriate numbers, right-aligned, on the column's cells. If the user begins editing one of the cells, the default cell editor uses a right-aligned JTextField to control the cell editing.

To choose the renderer that displays the cells in a column, a table first determines whether you specified a renderer for that particular column. (We'll tell you how to specify renderers a bit later.) If you didn't, then the table invokes the table model's getColumnClass method, which gets the data type of the column's cells. Next, the table compares the column's data type with a list of data types for which cell renderers are registered. This list is initialized by the table, but you can add to it or change it. Currently, tables put the following types of data in the list:

  • Boolean — rendered with a check box.
  • Number — rendered by a right-aligned label.
  • Double, Float — same as Number, but the object-to-text translation is performed by a NumberFormat (in the API reference documentation) instance (using the default number format for the current locale).
  • Date — rendered by a label, with the object-to-text translation performed by a DateFormat (in the API reference documentation) instance (using a short style for the date and time).
  • ImageIcon, Icon — rendered by a centered label.
  • Object — rendered by a label that displays the object's string value.

Version note: The default renderer associations for Double, Float, and Icon were added in 1.3.

Cell editors are chosen using a similar algorithm.

Remember that if you let a table create its own model, it uses Object as the type of every column. To specify more precise column types, the table model must define the getColumnClass method appropriately, as demonstrated by TableDemo.java (in a .java source file).

Keep in mind that although renderers determine how each cell or column header looks and can specify its tool tip text, renderers don't handle events. If you need to pick up the events that take place inside a table, the technique you use varies by the sort of event you're interested in:

Situation How to Get Events
To detect events from a cell that's being edited... Use the cell editor (or register a listener on the cell editor).
To detect row/column/cell selections and deselections... Use a selection listener as described in Detecting User Selections.
To detect mouse events on a column header... Register the appropriate type of mouse listener  (in the Creating a GUI with JFC/Swing trail) on the table's JTableHeader object. (See TableSorter.java (in a .java source file) for an example.)
To detect other events... Register the appropriate listener on the JTable object.

The next few sections tell you how to customize display and editing by specifying renderers and editors. You can specify cell renderers and editors either by column or by data type.

Using a Combo Box as an Editor

Setting up a combo box as an editor is simple, as the following example shows. The bold line of code sets up the combo box as the editor for a specific column.
TableColumn sportColumn = table.getColumnModel().getColumn(2);
...
JComboBox comboBox = new JComboBox();
comboBox.addItem("Snowboarding");
comboBox.addItem("Rowing");
comboBox.addItem("Chasing toddlers");
comboBox.addItem("Speed reading");
comboBox.addItem("Teaching high school");
comboBox.addItem("None");
sportColumn.setCellEditor(new DefaultCellEditor(comboBox));
Here is a picture of the combo box editor in use:

A combo box cell editor in use

[PENDING: This figure will be updated. It should probably include the cursor.]

The preceding code is from TableRenderDemo.java (in a .java source file). You can run TableRenderDemo using Java Web Start (in the Creating a GUI with JFC/Swing trail).

Using an Editor to Validate User-Entered Text

If a cell's default editor allows text entry, you get some error checking for free if the cell's type is specified as something other than String or Object. The error checking is a side effect of converting the entered text into an object of the proper type.

Version note: Before 1.3, the default implementation did not in any way restrict the string that could be entered, and didn't convert it from a String. You needed to put some ugly code in the model's setValueAt method to parse the entered string and prevent the cell's value from becoming a String.

The automatic checking of user-entered strings occurs when the default editor attempts to create a new instance of the class associated with the cell's column. The default editor creates this instance using a constructor that takes a String as an argument. For example, in a column whose cells have type Integer, when the user types in "123" the default editor creates the corresponding Integer using code equivalent to new Integer("123"). If the constructor throws an exception, the cell's outline turns red and refuses to let focus move out of the cell. If you implement a class used as a column data type, you can use the default editor if your class supplies a constructor that takes a single argument of type String.

If you like having a text field as the editor for a cell, but want to customize it — perhaps to check user-entered text more strictly or to react differently when the text is invalid — you can change the cell editor to use a formatted text field. The formatted text field can check the value either continuously while the user is typing or after the user has indicated the end of typing (such as by pressing Enter).

The following code, taken from a demo named TableFTFEditDemo, sets up a formatted text field as an editor that limits all integer values to be between 0 and 100. You can run TableFTFEditDemo using Java Web Start (in the Creating a GUI with JFC/Swing trail). The following code makes the formatted text field the editor for all columns that contain data of type Integer.

table.setDefaultEditor(Integer.class,
                       new IntegerEditor(0, 100));
The IntegerEditor class is implemented as a subclass of DefaultCellEditor (in the API reference documentation) that uses a JFormattedTextField instead of the JTextField that DefaultCellEditor supports. It accomplishes this by first setting up a formatted text field to use an integer format and have the specified minimum and maximum values, using the API described in How to Use Formatted Text Fields. It then overrides the DefaultCellEditor implementation of the getTableCellEditorComponent, getCellEditorValue, and stopCellEditing methods, adding the operations that are necessary for formatted text fields.

The override of getTableCellEditorComponent sets the formatted text field's value property (and not just the text property it inherits from JTextField) before the editor is shown. The override of getCellEditorValue keeps the cell value as an Integer, rather than, say, the Long value that the formatted text field's parser tends to return. Finally, overriding stopCellEditing lets us check whether the text is valid, possibly stopping the editor from being dismissed. If the text isn't valid, our implementation of stopCellEditing puts up a dialog that gives the user the option of continuing to edit or reverting to the last good value. The source code is a bit too long to include here, but you can find it in IntegerEditor.java (in a .java source file).

Using Other Editors

Whether you're setting the editor for a single column of cells (using the TableColumn setCellEditor method) or for a specific type of data (using the JTable setDefaultEditor method), you specify the editor using an argument that adheres to the TableCellEditor interface. Fortunately, the DefaultCellEditor class implements this interface and provides constructors to let you specify an editing component that's a JTextField, JCheckBox, or JComboBox. You usually don't have to explicitly specify a check box as an editor, since columns with Boolean data automatically use a check box renderer and editor.

What if you want to specify an editor that isn't a text field, check box, or combo box? Well, because DefaultCellEditor doesn't support other types of components, you must do a little more work. You need to create a class that implements the TableCellEditor (in the API reference documentation) interface. The AbstractCellEditor (in the API reference documentation) class is a good superclass to use. It implements TableCellEditor's superinterface, CellEditor (in the API reference documentation), saving you the trouble of implementing the event firing code necessary for cell editors.

Your cell editor class needs to define at least two methods — getCellEditorValue and getTableCellEditorComponent. The getCellEditorValue method, required by CellEditor, returns the cell's current value. The getTableCellEditorComponent method, required by TableCellEditor, should configure and return the component that you want to use as the editor.


Version note: The AbstractCellEditor class was added in 1.3. Before then, implementing a cell editor for a new component type was much more difficult, since you had to implement all the CellEditor methods yourself.

Here is a picture of a table with a dialog that serves, indirectly, as a cell editor. When the user begins editing a cell in the Favorite Color column, a button (the true cell editor) appears and brings up the dialog, with which the user can choose a different color.

The cell editor brings up a dialog

[PENDING: This figure will be updated.]

You can run TableDialogEditDemo using Java Web Start (in the Creating a GUI with JFC/Swing trail), or compile and run it yourself by consulting the example index. Here is the code, taken from ColorEditor.java (in a .java source file), that implements the cell editor.

public class ColorEditor extends AbstractCellEditor
                         implements TableCellEditor,
                                    ActionListener {
    Color currentColor;
    JButton button;
    JColorChooser colorChooser;
    JDialog dialog;
    protected static final String EDIT = "edit";

    public ColorEditor() {
        button = new JButton();
        button.setActionCommand(EDIT);
        button.addActionListener(this);
        button.setBorderPainted(false);

        //Set up the dialog that the button brings up.
        colorChooser = new JColorChooser();
        dialog = JColorChooser.createDialog(button,
                                        "Pick a Color",
                                        true,  //modal
                                        colorChooser,
                                        this,  //OK button handler
                                        null); //no CANCEL button handler
    }

    public void actionPerformed(ActionEvent e) {
        if (EDIT.equals(e.getActionCommand())) {
            //The user has clicked the cell, so
            //bring up the dialog.
            button.setBackground(currentColor);
            colorChooser.setColor(currentColor);
            dialog.setVisible(true);

            fireEditingStopped(); //Make the renderer reappear.

        } else { //User pressed dialog's "OK" button.
            currentColor = colorChooser.getColor();
        }
    }

    //Implement the one CellEditor method that AbstractCellEditor doesn't.
    public Object getCellEditorValue() {
        return currentColor;
    }

    //Implement the one method defined by TableCellEditor.
    public Component getTableCellEditorComponent(JTable table,
                                                 Object value,
                                                 boolean isSelected,
                                                 int row,
                                                 int column) {
        currentColor = (Color)value;
        return button;
    }
}
As you can see, the code is pretty simple. The only part that's a bit tricky is the call to fireEditingStopped at the end of the editor button's action handler. Without this call, the editor would remain active, even though the modal dialog is no longer visible. The call to fireEditingStopped lets the table know that it can deactivate the editor, letting the cell be handled by the renderer again.

Using Custom Renderers

This section tells you how to create and specify a cell renderer. You can set a type-specific cell renderer using the JTable method setDefaultRenderer. To specify that cells in a particular column should use a renderer, you use the TableColumn method setCellRenderer. You can even specify a cell-specific renderer by creating a JTable subclass, as we'll show later.

It's easy to customize the text or image rendered by the default renderer, DefaultTableCellRenderer. You just create a subclass and implement the setValue method so that it invokes setText or setIcon with the appropriate string or image. For example, here is how the default date renderer is implemented:

static class DateRenderer extends DefaultTableCellRenderer {
    DateFormat formatter;
    public DateRenderer() { super(); }

    public void setValue(Object value) {
        if (formatter==null) {
            formatter = DateFormat.getDateInstance();
        }
        setText((value == null) ? "" : formatter.format(value));
    }
}

If extending DefaultTableCellRenderer doesn't do the trick, you can build a renderer using another superclass. The easiest way is to create a subclass of an existing component, making your subclass implement the TableCellRenderer (in the API reference documentation) interface. TableCellRenderer requires just one method: getTableCellRendererComponent. Your implementation of this method should set up the rendering component to reflect the passed-in state, and then return the component.

In the preceding snapshot of TableDialogEditDemo, the renderer used for Favorite Color cells is a subclass of JLabel called ColorRenderer. Here are excerpts from ColorRenderer.java (in a .java source file) that show how it's implemented.

public class ColorRenderer extends JLabel
                           implements TableCellRenderer {
    ...
    public ColorRenderer(boolean isBordered) {
        this.isBordered = isBordered;
        setOpaque(true); //MUST do this for background to show up.
    }

    public Component getTableCellRendererComponent(
                            JTable table, Object color,
                            boolean isSelected, boolean hasFocus,
                            int row, int column) {
        Color newColor = (Color)color;
        setBackground(newColor);
        if (isBordered) {
            if (isSelected) {
                ...
                //selectedBorder is a solid border in the color
                //table.getSelectionBackground().
                setBorder(selectedBorder);
            } else {
                ...
                //unselectedBorder is a solid border in the color
                //table.getBackground().
                setBorder(unselectedBorder);
            }
        }
        
        setToolTipText(...); //Discussed in the following section
        return this;
    }
}
Here is the code from TableDialogEditDemo.java (in a .java source file) that registers a ColorRenderer instance as the default renderer for all Color data:
table.setDefaultRenderer(Color.class, new ColorRenderer(true));

The next section shows a couple of examples of using TableColumn's setCellRenderer method, so we'll skip that for now and show you how to specify a renderer for a particular cell. To specify a cell-specific renderer, you need to define a JTable subclass that overrides the getCellRenderer method. For example, the following code makes the first cell in the first column of the table use a custom renderer:

TableCellRenderer weirdRenderer = new WeirdRenderer();
table = new JTable(...) {
    public TableCellRenderer getCellRenderer(int row, int column) {
        if ((row == 0) && (column == 0)) {
            return weirdRenderer;
        }
        // else...
        return super.getCellRenderer(row, column);
    }
};

Specifying Tool Tips for Cells

By default, the tool tip text displayed for a table cell is determined by the cell's renderer. However, sometimes it can be simpler to specify tool tip text by overriding JTable's implementation of the getToolTipText(MouseEvent) method. This section tells you how to use both techniques.

To add a tool tip to a cell using its renderer, you first need to get or create the cell renderer. Then, after making sure the rendering component is a JComponent, invoke the setToolTipText method on it.

An example of setting tool tips for cells is in TableRenderDemo, which you can run using Java Web Start (in the Creating a GUI with JFC/Swing trail). The source code is in TableRenderDemo.java (in a .java source file). It adds tool tips to the cells of the Sport column with the following code:

//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
        new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
sportColumn.setCellRenderer(renderer);
Here is a picture of the resulting tool tip:

[PENDING: We will put a picture here. It might be cropped to just include the relevant cell and its tool tip (along with whatever other cells are between them).]

Although the tool tip text in the previous example is static, you can also implement tool tips whose text changes depending on the state of the cell or program. Here are a couple ways to do so:

  • Add a bit of code to the renderer's implementation of the getTableCellRendererComponent method.
  • Override the JTable method getToolTipText(MouseEvent).

An example of adding code to a cell renderer is in TableDialogEditDemo (which you can run using Java Web Start (in the Creating a GUI with JFC/Swing trail)). TableDialogEditDemo uses a renderer for colors, implemented in ColorRenderer.java (in a .java source file), that sets the tool tip text using the boldface code in the following snippet:

public class ColorRenderer extends JLabel 
                           implements TableCellRenderer {
    ...
    public Component getTableCellRendererComponent(
                            JTable table, Object color,
                            boolean isSelected, boolean hasFocus,
                            int row, int column) {
        Color newColor = (Color)color;
        ...
        setToolTipText("RGB value: " + newColor.getRed() + ", "
                                     + newColor.getGreen() + ", "
                                     + newColor.getBlue());
        return this;
    }
}
Here is an example of what the tool tip looks like:

TableDialogEditDemo with a tool tip describing the moused-over cell's RGB value

[PENDING: this snapshot needs to be updated. It should probably be cropped, as well.]

As we mentioned before, you can specify tool tip text by overriding JTable's getToolTipText(MouseEvent) method. The program TableToolTipsDemo shows how. You can run TableToolTipsDemo using Java Web Start (in the Creating a GUI with JFC/Swing trail). The cells with tool tips are in the Sport and Vegetarian columns. Here's are pictures of their tool tips:

[PENDING: put a picture here. It could be cropped to just include the relevant cell and its tool tip (along with whatever other cells are between them).]

TableToolTipsDemo with a tool tip for a cell in the Vegetarian column

[PENDING: this snapshot needs to be updated and cropped.]

Here is the code from TableToolTipsDemo.java (in a .java source file) that implements tool tips for cells in the Sport and Vegetarian columns:

JTable table = new JTable(new MyTableModel()) {    
    //Implement table cell tool tips.
    public String getToolTipText(MouseEvent e) {
        String tip = null;
        java.awt.Point p = e.getPoint();
        int rowIndex = rowAtPoint(p);
        int colIndex = columnAtPoint(p);
        int realColumnIndex = convertColumnIndexToModel(colIndex);

        if (realColumnIndex == 2) { //Sport column
            tip = "This person's favorite sport to "
                   + "participate in is: "
                   + getValueAt(rowIndex, colIndex);

        } else if (realColumnIndex == 4) { //Veggie column
            TableModel model = getModel();
            String firstName = (String)model.getValueAt(rowIndex,0);
            String lastName = (String)model.getValueAt(rowIndex,1);
            Boolean veggie = (Boolean)model.getValueAt(rowIndex,4);
            if (Boolean.TRUE.equals(veggie)) {
                tip = firstName + " " + lastName
                      + " is a vegetarian";
            } else {
                tip = firstName + " " + lastName
                      + " is not a vegetarian";
            }

        } else { //another column
            //You can omit this part if you know you don't 
            //have any renderers that supply their own tool 
            //tips.
            tip = super.getToolTipText(e);
        }
        return tip;
    }
    ...
}
The code is fairly straightforward, except perhaps for the call to convertColumnIndexToModel. That call is necessary because if the user moves the columns around, the view's index for the column doesn't match the model's index for the column. For example, the user might drag the Vegetarian column (which the model considers to be at index 4) so it's displayed as the first column — at view index 0. Since prepareRenderer gives us the view index, we need to translate the view index to a model index so we can be sure we're dealing with the intended column.

Specifying Tool Tips for Column Headers

You can add a tool tip to a column header by setting the tool tip text for the table's JTableHeader. Often, different column headers require different tool tip text. You can change the text by overriding the table header's getToolTipText(MouseEvent) method.

An example of using the same tool tip text for all column headers is in TableSorterDemo. Here is how it sets the tool tip text:

table.getTableHeader().setToolTipText(
        "Click to sort; Shift-Click to sort in reverse order");

TableToolTipsDemo has an example of implementing column header tool tips that vary by column. If you run TableToolTipsDemo, which you can do using Java Web Start (in the Creating a GUI with JFC/Swing trail), you'll see the tool tips when you mouse over any column header except for the first two. We elected not to supply tool tips for the name columns since they seemed self explanatory. (Actually, we just wanted to show you that it could be done.) Here's a picture of one of the column header tool tips:

TableToolTipsDemo with a tool tip for a column header

[PENDING: this snapshot needs to be updated. It should also be cropped.]

The following code implements the tool tips. Basically, it creates a subclass of JTableHeader that overrides the getToolTipText(MouseEvent) method so that it returns the text for the current column. To associate the revised table header with the table, the JTable method createDefaultTableHeader is overridden so that it returns an instance of the JTableHeader subclass.

protected String[] columnToolTips = {
    null,
    null,
    "The person's favorite sport to participate in",
    "The number of years the person has played the sport",
    "If checked, the person eats no meat"};
...

JTable table = new JTable(new MyTableModel()) {
    ...

    //Implement table header tool tips.
    protected JTableHeader createDefaultTableHeader() {
        return new JTableHeader(columnModel) {
            public String getToolTipText(MouseEvent e) {
                String tip = null;
                java.awt.Point p = e.getPoint();
                int index = columnModel.getColumnIndexAtX(p.x);
                int realIndex = 
                        columnModel.getColumn(index).getModelIndex();
                return columnToolTips[realIndex];
            }
        };
    }
};

Version note: Before 1.3, each column had its own header renderer, and you could use the value returned by the TableColumn method getHeaderRenderer to set a tool tip for a specific column header. For performance reasons, the default behavior is now to use a single renderer for all column headers, and getHeaderRenderer returns null. The default header renderer used for all columns is returned by the TableHeader method getDefaultRenderer, which was added in 1.3.

Sorting and Otherwise Manipulating Data

One way to perform data manipulation such as sorting is to use one or more specialized table models (data manipulators), in addition to the table model that provides the data (the data model). The data manipulators should sit between the table and the data model, as the following picture shows:

A data manipulator sits between a table and its model.

[PENDING: This figure will be updated.]

If you decide to implement a data manipulator, take a look at TableMap.java (in a .java source file) and TableSorter.java (in a .java source file). The TableMap class implements TableModel and serves as a superclass for data manipulators. TableSorter is a data manipulator that sorts the data provided by another table model. It used to be implemented as a subclass of TableMap, but now is a direct subclass of AbstractTableModel. You can use TableSorter as-is to provide sorting functionality, or you can use either TableSorter or TableMap as a basis for writing your own data manipulator.

To implement sorting with TableSorter, you need just three lines of code. The following listing shows the differences between TableDemo and its sorting cousin, TableSorterDemo.java (in a .java source file).

TableSorter sorter = new TableSorter(new MyTableModel()); //ADDED THIS
//JTable table = new JTable(new MyTableModel());          //OLD
JTable table = new JTable(sorter);             //NEW
sorter.setTableHeader(table.getTableHeader()); //ADDED THIS

Note: The TableSorter class was updated in February, 2004. We recommend the newer version, as it has more features and fixes several bugs. If you currently use the old version, you can update to the new one by deleting TableMap.java and making the following change in the code that sets up the sorter:
//sorter.addMouseListenerToHeaderInTable(table); //OLD
sorter.setTableHeader(table.getTableHeader());   //NEW

The setTableHeader method sets up the table's column headers to detect user clicks and update the UI appropriately. When the user clicks, the sorter sorts the rows based on the clicked column. As the following snapshot shows, when you click "Last Name", the rows are reordered so that the row with "Campione" becomes the first row.

TableSorterDemo after clicking Last Name

[PENDING: This figure will be updated.]

You can add secondary sorting by Control-clicking additional columns. For example, by clicking the Vegetarian column and then Control-clicking the Last Name column, you get an alphabetized listing of vegetarians followed by an alphabetized listing of omnivores.

[PENDING: We will add a figure showing secondary sorting.]

You can change the clicking behavior by reimplementing the MouseHandler class defined in TableSorter.java.

The Table API

The tables in this section cover just part of the table API. For more information about the table API, see the API documentation for JTable (in the API reference documentation) and for the various classes and interfaces in the table package (in the API reference documentation). Also see The JComponent Class, which describes the API that JTable inherits from JComponent. The API for using tables falls into the following categories:

Table-Related Classes and Interfaces
Class or Interface Purpose
JTable The component that presents the table to the user.
JTableHeader The component that presents the column names to the user. By default, the table generates this component automatically.
TableModel
AbstractTableModel
Respectively, the interface that a table model must implement and the usual superclass for table model implementations.
TableCellRenderer
DefaultTableCellRenderer
Respectively, the interface that a table cell renderer must implement and the usual implementation used.
TableCellEditor
DefaultCellEditor
AbstractCellEditor
Respectively, the interface that a table cell editor must implement, the usual implementation used, and the usual superclass for table cell editor implementations.
TableColumnModel
DefaultTableColumnModel
Respectively, the interface that a table column model must implement and the usual implementation used. You don't usually need to deal with the table column model directly unless you need to get the column selection model, or get a column index or object.
TableColumn Controls all the attributes of a table column, including resizability; minimum, preferred, current, and maximum widths; and an optional column-specific renderer/editor.
DefaultTableModel A Vector-based table model used by JTable when you construct a table specifying no data model and no data.
TableModelListener The interface that an object must implement to be notified of changes to the TableModel.
ListSelectionListener The interface that an object must implement to be notified of changes to the table's selection.

Creating and Setting Up a Table
Constructor or Method Purpose
JTable(TableModel)
JTable(TableModel, TableColumnModel)
JTable(TableModel, TableColumnModel, ListSelectionModel)
JTable()
JTable(int, int)
JTable(Object[][], Object[])
JTable(Vector, Vector)
Create a table. The optional TableModel argument specifies the model that provides the data to the table. The optional TableColumnModel and ListSelectionModel arguments let you specify the table column model and the row selection model. As an alternative to specifying a table model, you can supply data and column names, using arrays or vectors. Another option is to specify no data, optionally specifying the number of rows and columns (both integers) to be in the table.
void setPreferredScrollableViewportSize(Dimension) Set the size of the visible part of the table when it's viewed within a scroll pane.
JTableHeader getTableHeader() Get the component that displays the column names.

Manipulating Columns
Constructor or Method Purpose
TableColumnModel getColumnModel()
(in JTable)
Get the table's column model.
TableColumn getColumn(int)
Enumeration getColumns()
(in TableColumnModel)
Get one or all of the TableColumn objects for the table.
void setMinWidth(int)
void setPreferredWidth(int)
void setMaxWidth(int)
(in TableColumn)
Set the minimum, preferred, or maximum width of the column.
int getMinWidth()
int getPreferredWidth()
int getMaxWidth()
int getWidth()
(in TableColumn)
Get the minimum, preferred, maximum, or current width of the column.

Using Editors and Renderers
Method Purpose
void setDefaultRenderer(Class, TableCellRenderer)
void setDefaultEditor(Class, TableCellEditor)
(in JTable)
Set the renderer or editor used, by default, for all cells in all columns that return objects of the specified type.
void setCellRenderer(TableCellRenderer)
void setCellEditor(TableCellEditor)
(in TableColumn)
Set the renderer or editor used for all cells in this column.
TableCellRenderer getHeaderRenderer()
(in TableColumn)
Get the header renderer for this column.

Version Note:  As of 1.3, this method returns null if the column uses the default renderer. You generally use the TableHeader method getDefaultRenderer instead.

TableCellRenderer getDefaultRenderer()
(in JTableHeader)
Get the header renderer used when none is defined by a table column. Introduced in 1.3.

Implementing Selection
Method Purpose
void setSelectionMode(int) Set the selection intervals allowed in the table. Valid values are defined in ListSelectionModel (in the API reference documentation) as SINGLE_SELECTION, SINGLE_INTERVAL_SELECTION, and MULTIPLE_INTERVAL_SELECTION (the default).
void setSelectionModel(ListSelectionModel)
ListSelectionModel getSelectionModel()
Set or get the model used to control row selections.
void setRowSelectionAllowed(boolean)
void setColumnSelectionAllowed(boolean)
void setCellSelectionEnabled(boolean)
Set the table's selection orientation. The boolean argument specifies whether that particular type of selection is allowed. By default, row selection is allowed, and column and cell selection are not.

Examples that Use Tables

This table lists examples that use JTable and where those examples are described.

Example Where Described Notes
SimpleTableDemo Creating a Simple Table A basic table with no custom model. Does not include code to specify column widths or detect user editing.
SimpleTable-
SelectionDemo
Detecting User Selections Adds single selection and selection detection to SimpleTableDemo. By modifying the program's ALLOW_COLUMN_SELECTION and ALLOW_ROW_SELECTION constants, you can experiment with alternatives to the table default of allowing only rows to be selected.
TableDemo Creating a Table Model A basic table with a custom model.
TableFTFEditDemo Using an Editor to Validate User-Entered Text Modifies TableDemo to use a custom editor (a formatted text field variant) for all Integer data.
TableRenderDemo Using a Combo Box as an Editor Modifies TableDemo to use a custom editor (a combo box) for all data in the Sport column. Also intelligently picks column sizes. Uses renderers to display tool tips for the sport cells.
TableDialogEditDemo Using Other Editors Modifies TableDemo to have a cell renderer and editor that display a color and let you choose a new one, using a color chooser dialog.
TableToolTipsDemo Specifying Tool Tips for Cells, Specifying Tool Tips for Column Headers, Demonstrates how to use several techniques to set tool tip text for cells and column headers.
TableSorterDemo Sorting and Otherwise Manipulating Data Sorts column data by interposing a data manipulating table model between the data model and the table. Detects user clicks on column headers.
ListSelectionDemo How to Write a List Selection Listener Shows how to use all list selection modes, using a list selection listener that's shared between a table and list.
SharedModelDemo Nowhere Builds on ListSelectionDemo making the data model be shared between the table and list. If you edit an item in the first column of the table, the new value is reflected in the list.
TreeTable, TreeTable II Creating TreeTables in Swing, Creating TreeTables: Part 2 Examples that combine a tree and table to show detailed information about a hierarchy such as a file system. The tree is a renderer for the table.


Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Copyright 1995-2004 Sun Microsystems, Inc. All rights reserved.

'java UI' 카테고리의 다른 글

File Connection Optiobal Package  (0) 2006.02.28
[펌] DataSource의 복제를 통한 다중 플레이어 생성방법  (0) 2005.12.02
jtable tutorial  (0) 2005.02.16
The Eclipse runtime options  (0) 2005.02.15
www.eclipse-plugins.info 의 순위  (0) 2005.02.12
BEYOND THE BASICS OF JOPTIONPANE  (0) 2005.02.11
Posted by 김용환 '김용환'

댓글을 달아 주세요

함수 포인터

c or linux 2005. 2. 16. 05:47

오늘은 함수 포인터에 대해서 배워 보겠습니다.

함수 포인터는 말 그대로 함수를 가리키는 포인터 변수입니다. 여태껏 배워왔던 포인터와 똑같습니다.

여태껏 변수만을 가리키는 방법을 배워왔습니다.

하지만 포인터 변수는 함수도 가리킬수 있는 강력한 권한이 있습니다. 

저번에도 얘기했듯이 포인터 변수는 모두 4Byte입니다.

여지껏 배워온 포인터의 또다른 기법을 배워야 할것입니다.

포인터 변수에 함수의 시작번지를 저장시키고 저장된 시작번지의 주소를 가리키게 한후 실제 함수를

호출 하게 하면 끝입니다..

선언 하는 방법도 함수와 비슷하게 선언해줘야 합니다.

그래야 함수를 가리키는 포인터라고 인식을 하는거죠..

예를들어 다음과 같이 Start라는 함수가 있다고 봅시다.

이것을 포인터 변수가 가리키도록 해볼까요?

void Start()
{
   printf("안녕하세요");
}

void (*p)(); //함수를 가리키는 포인터 변수 4Byte짜리를 선언한다.

p = Start; // Start함수의 선두번지의 주소를 p포인터 변수가 가리킬수 있도록 p에 저장한다.

(*p)(); // p에 *를 붙이고 뒤에 ();를 붙여서 p가 가리키는 함수를 호출한다.

자 여기서 (*p)빼고는 Start와 리턴형과 파라미터가 없는것이 비슷합니다.

Start함수를 가리키기 위해서는 가리키는 함수와 똑같이 파라미터와 리턴값을 맞춰줘야 합니다.

void Start()
void (*p)()

자 (*p)와 이름만 틀릴뿐 비슷하죠?

자 여기서 *p가 붙어 함수를 가리키는 포인터 변수가 선언이 된것입니다.

함수를 가리키는 포인터 변수만 선언이 된것이지요.

포인터 변수에 Start함수의 시작주소를 저장시켜 볼까요?

p = Start;

Start 이름 자체는 함수의 시작번지를 가지고 있는 상수입니다!!!!!

그러므로 Start의 시작번지를 p에 저장하는 것입니다.

p가 가리키는 함수를 호출 해볼까요?

앞에 *를 붙여주면 자신이 가리키는 주소를 찾아가죠. 그리고 뒤에 ();를 붙여 함수를 찾아가라고

인식을 시켜줘야 합니다.

(*p)();를 호출하면 결국 Start();로 호출하는거와 똑같은 결과가 나타납니다.

결국 p가 가리키는 함수의 시작번지를 찾아가 Start()를 호출하는거죠.

자 다른 예제를 봅시다. 리턴값과 파라미터에 값을 전달하는 것입니다.

int Sum(int a, int b)
{
 printf("합은 [%d] 입니다",a+b);
 return a+b;
}

void main()
{
 int (*p)(int a, int b); //함수를 가리킬 수 있도록 포인터 변수 선언( 함수와 비슷하게 )

 p = Sum; //Sum함수의 선두번지를 p포인터에 저장

 int Value = (*p)(10,10); // p포인터가 가리키는 함수를 호출 리턴값을 Value에 저장

 printf("\r\n리턴값:%d", Value);
}

<결과>

합은 [20] 입니다
리턴값:20

다똑같죠 단지 (*p)이것만 해줬을 뿐이죠.

int Sum(int a, int b)를 가리키려면 반드시

int (*p)(int a, int b); <-- 이렇게 똑같은 형태로 변수를 선언해야 합니다.

(*p)이름을 변수처럼 자유롭게 사용할수 있죠..

포인터 변수라고 우선순위를 주기 위해서 괄호를 넣어 준것이구요.

아무튼 약간 이상해 보일지도 모르겠지만 이렇게 사용한다고 이해를 해두셔야 합니다.

마지막으로 알아야 할것은 함수를 가리키는 포인터 변수는 파라미터로 받을 수 있습니다.

당연히 변수니깐 파라미터로 받겠죠.

다음 예제를 봅시다.

void Hello()
{
  printf("Hello");
}

void Okay(void (*p)()) //파라미터를 함수를 가리키는 포인터로 파라미터를 받았습니다.
{
  (*p)(); //파라미터로 넘겨받은 선두번지를 찾아가 Hello함수를 실행합니다.
}

void main()
{
  Okay(Hello); // Hello함수의 선두번지를 파라미터로 넘겨준다.
}

이런식으로 아주 간단하게 넘길 수가 있습니다.

Okay파라미터에 void (*p)()를 그대로 넣어 줬습니다.

왜냐 함수를 가리키는 포인터는 변수이고 함수를 가리키기 위해서는 포인터 변수를 함수처럼

(*p)만 빼고 똑같이 선언해줘야 한다고 배웠습니다.

아무튼 리턴값과 파라미터는 항상 똑같이 해주어야 합니다 결코 잊지 마세요!

이상 함수 포인터를 마치겠습니다.

'c or linux' 카테고리의 다른 글

pthread 개념 - Application Development Guide --Core Components  (0) 2005.02.18
POSIX 쓰레드로 멀티 쓰레드 프로그래밍하기  (0) 2005.02.18
함수 포인터  (0) 2005.02.16
ctags 활용  (0) 2005.02.15
#ifdef __cplusplus  (1) 2005.02.12
Setjmp()  (0) 2005.02.11
Posted by 김용환 '김용환'

댓글을 달아 주세요

http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/org.eclipse.platform.doc.isv/reference/misc/runtime-options.html

 

The Eclipse runtime options

Last modified 14:45 Wednesday August 4, 2004

The Eclipse platform is highly configurable. Configuration input takes the form of command line arguments and System property settings. In many cases the command line arguments are simply short cuts for setting the related System properties. In fact, there are many more System property settings than command line arguments.

Command line arguments

Listed below are the command line arguments processed by various parts of the Eclipse runtime. Many of these values can also be specified using System properties either on the command line using -D VM arguments or by specifying there values in a config.ini file. Using this latter technique it is possible to customize your Eclipse without using command line arguments at all.

For each argument in the list, its corresponding System property key is given (in {}). Also given is the Eclipse runtime layer in which the command line argument is processed (in ()). This is useful for people replacing parts of the runtime to suit special needs.

-application <id> (Runtime)
equivalent to setting eclipse.application to <id>
-arch <architecture> (OSGi)
equivalent to setting osgi.arch to <architecture>
-clean (OSGi) NEW
equivalent to setting osgi.clean to "true"
-configuration <location> (Main)
equivalent to setting osgi.configuration.area to <location>
-console [port] (OSGi) NEW
equivalent to setting osgi.console to [port] or the empty string if the default port is to be used (i.e., when the port is not specified)
-consoleLog (Runtime)
equivalent to setting eclipse.consoleLog to "true"
-data <location> (OSGi)
equivalent to setting osgi.instance.area to <location>
-debug [options file] (OSGi)
equivalent to setting osgi.debug to [options file] or the empty string to simply enable debug (i.e., if the options file location is not specified)
-dev [entries] (OSGi)
equivalent to setting osgi.dev to [entries] or the empty string to simply enable dev mode (i.e., if entries are not specified)
-endSplash <command> (Main)
specifies the command to use to take down the splash screen. Typically supplied by the Eclipse executable.
-feature <feature id> (Runtime)
equivalent to setting eclipse.product to <feature id>
-framework <location> (Main) NEW
equivalent to setting osgi.framework to <location>
-initialize (Main)
initializes the configuration being run. All runtime related data structures and caches are refreshed. Any user/plug-in defined configuration data is not purged. No application is run, any product specifications are ignored and no UI is presented (e.g., the splash screen is not drawn)
-install <location> (Main)
equivalent to setting osgi.install.area to <location>
-keyring <location> (Runtime)
the location of the authorization database on disk. This argument has to be used together with the -password argument.
-nl <locale> (OSGi)
equivalent to setting osgi.nl to <locale>
-noLazyRegistryCacheLoading (Runtime)
equivalent to setting eclipse.noLazyRegistryCacheLoading to "true"
-noRegistryCache (Runtime)
equivalent to setting eclipse.noRegistryCache to "true"
-noSplash (Executable, Main)
controls whether or not the splash screen is shown
-os <operating system> (OSGi)
equivalent to setting osgi.os to <operating system>
-password <password> (Runtime)
the password for the authorization database
-pluginCustomization <location> (Runtime)
equivalent to setting eclipse.pluginCustomization to <location>
-product <id> (OSGi) NEW
equivalent to setting eclipse.product to <id>
-showSplash <command> (Main)
specifies the command to use to show the splash screen. Typically supplied by the Eclipse executable.
-user <location> (OSGi) NEW
equivalent to setting osgi.user.area to <location>
-vm <path to java executable> (Executable, Main) NEW
when passed to the Eclipse executable, this option is used to locate the Java VM to use to run Eclipse. It must be the full filesystem path to an appropriate Java executable. If not specified, the Eclipse executable uses a search algorithm to locate a suitable VM. In any event, the executable then passes the path to the actual VM used to Java Main using the -vm argument. Java Main then stores this value in eclipse.vm.
-vmargs [vmargs*] (Executable, Main) NEW
when passed to the Eclipse, this option is used to customize the operation of the Java VM to use to run Eclipse. If specified, this option must come at the end of the command line. Even if not specified on the executable command line, the executable will automatically add the relevant arguments (including the class being launched) to the command line passed into Java using the -vmargs argument. Java Main then stores this value in eclipse.vmargs.
-ws <window system> (OSGi)
equivalent to setting osgi.ws to <window system>

Obsolete command line arguments

The following command line arguments are no longer relevant or have been superceded and are consumed by the runtime and not passed on to the application being run to maintain backward compatibility. .

-boot
see -configuration
-classLoaderProperties
no longer relevant
-firstUse
no longer relevant
-newUpdates
no longer relevant
-noPackagePrefixes
no longer relevant
-noUpdate
no longer relevant
-plugins
no longer relevant
-update
no longer relevant

Others

The following command line arguments are defined by various Eclipse plug-ins and are only supported if the defining plug-in is installed, resolved and activated.

-noVersionCheck (workbench)
<description>
-perspective (workbench)
<description>
-refresh (org.eclipse.core.resources)
<description>
-showLocation (org.eclipse.ui.ide.workbench)
<description>
-allowDeadlock
<description>

System properties

The following System properties are used by the Eclipse runtime. Note that those starting with "osgi" are specific to the OSGi framework implementation while those starting with "eclipse" are particular to the Eclipse runtime layered on top of the OSGi framework.

Many of these properties have command line equivalents (see the command line arguments section and the value in braces {}). Users are free to use either command line or property settings to specify a value. Properties can be set in the following ways:

  • use -DpropName=propValue as a VM argument to the Java VM
  • set the desired property in the config.ini file in the appropriate configuration area
eclipse.application {-application}
the identifier of the application to run. The value given here overrides any application defined by the product (see eclipse.product) being run
eclipse.commands
sdf
eclipse.consoleLog
if "true", any log output is also sent to Java's System.out (typically back to the command shell if any). Handy when combined with -debug
eclipse.debug.startupTime
the time in milliseconds when the Java VM for this session was started
eclipse.exitcode
<description>
eclipse.exitdata
<description>
eclipse.manifestConverter
the class name of the manifest converter class to use when converting legacy plugin.xml files to manifest.mf files
eclipse.noExtensionMunging
if "true", legacy registry extension are left as-is. By default such extensions are updated to use the new extension point ids found in Eclipse 3.0.
eclipse.noLazyRegistryCacheLoading {-noLazyRegistryCacheLoading}
if "true", the platform's plug-in registry cache loading optimization is deactivated. By default, configuration elements are loaded from the registry cache (when available) only on demand, reducing memory footprint. This option forces the registry cache to be fully loaded at startup.
eclipse.noRegistryCache {-noRegistryCache}
if "true", the internal extension registry cache is neither read or written
eclipse.pluginCustomization {-pluginCustomization}
the file system location of a properties file containing default settings for plug-in preferences. These default settings override default settings specified in the primary feature. Relative paths are interpreted relative to the current working directory for eclipse itself.
eclipse.product {-product}
the identifier of the product being run. This controls various branding information and what application is used.
eclipse.vm {-vm}
the path to the Java executable used to run Eclipse. This information is used to construct relaunch command lines.
eclipse.vmargs {-vmargs}
lists the VM arguments used to run Eclipse. This information is used to construct relaunch command lines.
osgi.adaptor
the class name of the OSGi framework adaptor to use.
osgi.arch {-arch}
see -arch
osgi.baseConfiguration.area
asf
osgi.bundles
The comma-separated list of bundles which are automatically installed and optionally started once the system is up and running. Each entry is of the form:
    <URL | simple bundle location>[@ [<start-level>] [":start"]]
If the start-level (>0 integer) is omitted then the framework will use the default start level for the bundle. If the "start" tag is added then the bundle will be marked as started after being installed. Simple bundle locations are interepreted as relative to the framework's parent directory. The start-level indicates the OSGi start level at which the bundle should run. If this value is not set, the system computes an appropriate default.
osgi.clean
if set to "true", any cached data used by the OSGi framework and eclipse runtime will be wiped clean. This will clean the caches used to store bundle dependency resolution and eclipse extension registry data. Using this option will force eclipse to reinitialize these caches.
osgi.configuration.cascaded
if set to "true", this configuration is cascaded to a parent configuration. See the section on locations for more details.
osgi.configuration.area {-configuration}
the configuration location for this run of the platform. The configuration determines what plug-ins will run as well as various other system settings. See the section on locations for more details.
osgi.configuration.area.default
the default configuration location for this run of the platform. The configuration determines what plug-ins will run as well as various other system settings. This value (i.e., the default setting) is only used if no value for the osgi.configuration.area is set. See the section on locations for more details.
osgi.console {-console}
if set to a non-null value, the OSGi console (if installed) is enabled. If the value is a suitable integer, it is interpreted as the port on which the console listens and directs its output to the given port. Handy for investigating the state of the system.
osgi.console.class
the class name of the console to run if requested
osgi.debug {-debug}
if set to a non-null value, the platform is put in debug mode. If the value is a string it is interpreted as the location of the .options file. This file indicates what debug points are available for a plug-in and whether or not they are enabled. If a location is not specified, the platform searches for the .options file under the install directory.
osgi.dev {-dev}
if set to the empty string, dev mode is simply turned on. This property may also be set to a comma-separated class path entries which are added to the class path of each plug-in or a URL to a Java properties file containing custom classpath additions for a set of plug-ins. For each plug-in requiring a customized dev time classpath the file will contain an entry of the form
    <plug-in id>=<comma separated list of classpath entries to add>
where plug-in id "*" matches any plug-in not otherwise mentioned.
osgi.framework
the URL location of the OSGi framework. Useful if the Eclipse install is disjoint. See the section on locations for more details.
osgi.frameworkClassPath
a comma separated list of classpath entries for the OSGi framework implementation. Relative locations are interpreted as relateve to the framework location (see osgi.framework)
osgi.install.area {-install}
the install location of the platform. This setting indicates the location of the basic Eclipse plug-ins and is useful if the Eclipse install is disjoint. See the section on locations for more details.
osgi.instance.area {-data}
the instance data location for this session. Plug-ins use this location to store their data. For example, the Resources plug-in uses this as the default location for projects (aka the workspace). See the section on locations for more details.
osgi.instance.area.default
the default instance data location for this session. Plug-ins use this location to store their data. For example, the Resources plug-in uses this as the default location for projects (aka the workspace). This value (i.e., the default setting) is only used if no value for the osgi.instance.area is set. See the section on locations for more details.
osgi.manifest.cache
the location where generated manifests are discovered and generated. The default is in the configuration area but the manifest cache can be stored separately.
osgi.nl {-nl}
the name of the locale on which Eclipse platform will run. NL values should follow the standard Java locale naming conventions.
osgi.os {-os}
the operating system value. The value should be one of the Eclipse processor architecture names known to Eclipse (e.g., x86, sparc, ...).
osgi.splashLocation
the absolute URL location of the splash screen (.bmp file) to to show while starting Eclipse. This property overrides any value set in osgi.splashPath.
osgi.splashPath
a comma separated list of URLs to search for a file called splash.bmp. This property is overriden by any value set in osgi.splashLocation.
osgi.user.area {-user}
the location of the user area. The user area contains data (e.g., preferences) specific to the OS user and independent of any Eclipse install, configuration or instance. See the section on locations for more details.
osgi.user.area.default
the default location of the user area. The user area contains data (e.g., preferences) specific to the OS user and independent of any Eclipse install, configuration or instance. This value (i.e., the default setting) is only used if no value for the osgi.user.area is set. See the section on locations for more details.
osgi.ws {-ws}
the window system value. The value should be one of the Eclipse window system names known to Eclipse (e.g., win32, motif, ...).
osgi.syspath
<xxx still used? fix the name>

Locations

The Eclipse runtime defines a number of locations which give plug-in developers context for reading/storing data and Eclipse users a control over the scope of data sharing and visibility. Eclipse defines the following notions of location:

User (-user) {osgi.user.area} [@none, @noDefault, @user.home, @user.dir, filepath, url]
User locations are specific to, go figure, users. Typically the user location is based on the value of the Java user.home system property but this can be overridden. Information such as user scoped preferences and login information may be found in the user location.
Install (-install) {osgi.install.area} [@user.home, @user.dir, filepath, url]
An install location is where Eclipse itself is installed. In practice this location is the directory (typically "eclipse") which is the parent of the startup.jar or eclipse.exe being run. This location should be considered read-only to normal users as an install may be shared by many users. It is possible to set the install location and decouple startup.jar from the rest of Eclipse.
Configuration (-configuration) {osgi.configuration.area} [@none, @noDefault, @user.home, @user.dir, filepath, url]
Configuration locations contain files which identify and manage the (sub)set of an install to run. As such, there may be many configurations per install. Installs may come with a default configuration area but typical startup scenarios involve the runtime attempting to find a more writable configuration location.
Instance (-data) {osgi.instance.area} [@none, @noDefault, @user.home, @user.dir, filepath, url]
Instance locations contain user-defined data artifacts. For example, the Resources plug-in uses the instance area as the workspace location and thus the default home for projects. Other plugins are free to write whatever files they like in this location.

While users can set any of these locations, Eclipse will compute reasonable defaults if values are not given. The most common usecase for setting location is the instance area or, in the IDE context, the workspace. To run the default Eclipse configuration on a specific data set you can specify:

    eclipse -data c:\mydata

More detail

Locations are URLs. For simplicity, file paths are also accepted and automatically converted to file: URLs. For better control and convenience, there are also a number of predefined symbolic locations which can be used. Note that not all combinations of location type and symbolic value are valid. A table below details which combinations are possible. Since the default case is for all locations to be set, valid and writable, some plug-ins may fail in other setups even if they are listed as possible. For example, it is unreasonable to expect a plugin focused on user data (e.g., the Eclipse Resources plug-in) to do much if the instance area is not defined. It is up to plug-in developers to choose the setups they support and design their function accordingly.

@none
Indicates that the corresponding location should never be set either explicitly or to its default value. For example, an RCP style application which has no user data may use osgi.instance.area=@none to prevent extraneous files being written to disk. @none must not be followed by any additional path segments.
@noDefault
Forces a location to be undefined or explicitly defined (i.e., Eclipse will not automatically compute a default value). This is useful where you want to allow for data in the corresponding location but the Eclipse default value is not appropriate. @noDefault must not be followed by any additional path segments.
@user.home
Directs Eclipse to compute a location value relative to the user's home directory. @user.home can be followed by additional path segments. In all cases, the string "@user.home" is simply replaced with the value of the Java "user.home" System property. For example, setting
    osgi.instance.area=@user.home/myWorkspace
results in a value of
    file:/users/bob/myWorkspace
@user.dir
Directs Eclipse to compute a location value relative to the current working directory. @user.dir can be followed by additional path segments. In all cases, the string "@user.dir" is simply replaced with the value of the Java "user.dir" System property. For example, setting
    osgi.instance.area=@user.dir/myWorkspace
results in a value of
    file:/usr/share/eclipse/myWorkspace
location/value
supports default
file/URL
@none
@noDefault
@user.home
@user.dir
instance
yes
yes
yes
yes
yes
yes (default)
configuration
yes
yes
yes*
yes*
yes
yes
install
no
yes
no
no
yes
yes
user
yes
yes
yes
yes
yes
yes

* indicates that this setup is technically possible but pragmatically quite difficult to manage. In particular, without a configuration location the Eclipse runtime may only get as far as starting the OSGi framework.

Legal notices.

'java UI' 카테고리의 다른 글

File Connection Optiobal Package  (0) 2006.02.28
[펌] DataSource의 복제를 통한 다중 플레이어 생성방법  (0) 2005.12.02
jtable tutorial  (0) 2005.02.16
The Eclipse runtime options  (0) 2005.02.15
www.eclipse-plugins.info 의 순위  (0) 2005.02.12
BEYOND THE BASICS OF JOPTIONPANE  (0) 2005.02.11
Posted by 김용환 '김용환'

댓글을 달아 주세요

 How to Organize your Thesis
 Advice to Authors of Extended Abstracts
 How to write good systems paper (Loy Leven.)
 How to give a good research talk(Simon L. Jones)

 

논문을 어떻게 쓰는지에 대해서 알려주는 글.

Posted by 김용환 '김용환'

댓글을 달아 주세요

ctags 활용

c or linux 2005. 2. 15. 01:35

출처 - JOINC WIKI

 

ctags 를 이용하면, 사용자 정의 함수가 나왔을때, 함수가 정의되어 있는 쏘스파일로 바로 점프할수 있으며, 또한 바로 원래의 쏘스파일로 되돌아올수 있다. 이렇게 함으로써 쏘스분석에 드는 시간을 상당히 줄일수 있다.
이번 문서에는 사용자가 vi 를 사용하고 있다는 가정하에 ctags 의 사용법을 설명하도록 하겠다.

ctags 는 공개 소프트웨어 임으로 쉽게 얻을수 있을것이다. 리눅스의 경우 웬만한 배포판은 기본으로 포함되어 있으니, 바로 사용하면 된다. 만약 설치되어 있지 않다면 www.rpmfind.org이나 www.freshmeat.net 등의 사이트에서 구해서 설치하면 된다.

일단 분석하고자 하는 쏘스의 디렉토리로 이동한다. 그리고 아래와 같은 방법으로 실행하면 된다.

[root@localhost user_admin_file]# ctags *
위에서 ctags 는 현재 디렉토리에 있는 모든 파일에 대해서 tags 정보를 작성하도록 했는데, 현재 디렉토리 뿐만 아니라 모든 하위디렉토리에 대해서 tags 정보를 작성하고자 한다면 "-R" 옵션을 사용하면 된다.
[root@localhost user_admin_file]# ctags -R
ctags 명령을 실행시키고 나면, ctags를 실행한 디렉토리에 tags 란 파일이 생길것이다. 여기에 각 함수가 어느파일에 설치되어 있는지에 대한 정보가 들어 있고, vi 를 실행 시키면 tags 파일을 참조하여 해당 함수가 정의되어 있는 파일로 자동으로 이동하게 된다.
tags 파일은 아래와 같이 구성되어 있다.
hello hello.c /^void hello(void)$/;" f

각필드는 "tab" 으로 구분된다. 첫번째 필드는 함수이름, 두번째 필드는 함수가 정의된 파일의 이름, 세번째 필드는(vi 를 좀 다룰줄 아는 유저 라면 익숙한 문장일 것이다), 해당 파일에서 vi가 함수명을 찾아가도록 하기위한 vi command 이다. 4번째 필드는 해당 함수의 타입이다. "f" 라면 일반 C 함수라는 뜻이며, "c" 는 클래스에 선언된 멤버함수, "d" 는 define 된 값이란 뜻이다.


이제 vi 로 분석하고자 하는 쏘스파일을 열어보자. 분석하는 중에 hello() 라는 알수없는 함수가 나와서 이 함수의 원형이 있는곳으로 이동하고 싶을 때는 hello() 함수에 커서를 위치시키고 "Ctrl + ]" 를 누르면 된다. 그러면 곧바로 hello() 함수의 원형으로 이동하게 된다.
hello() 함수에 대한 분석이 끝나서, 원래 분석하던 쏘스 파일로 돌아오고 싶다면 "Ctrl + t"키를 누르면 된다.

 

.vimrc에 set tags=d:\work\ttt\g4\base\cvm_hi\tags 이런식으로 vi가 쓸수있도록 set tags를 하느 것을 잊지 말아야 한다. = 용환 write.

 

-------------------------------------------------------------------------------------------

출처 - man page : ctags

NAME


       ctags - Generate tag files for source code

SYNOPSIS


       ctags [options] [file(s)]

       etags [options] [file(s)]

DESCRIPTION


       The  ctags and etags programs (hereinafter collectively referred to as
       ctags, except where distinguished) generate an index (or "tag") file
       for  a  variety of  language objects found in file(s). This tag file
       allows these items to be quickly and easily located by a text  editor
       or  other  utility.  A  "tag" signifies a language object for which an
       index entry is available (or, alternatively, the index  entry  created
       for that object).

       Alternatively,  ctags can generate a cross reference file which lists,
       in human readable form, information about the various  source  objects
       found in a set of language files.

       Tag  index  files  are  supported by numerous editors, which allow the
       user to locate the object associated with a name appearing in a source
       file and jump to the file and line which defines the name. Those known
       about at the time of this release are:

   Vi(1) and its derivatives (e.g. Elvis, Vim, Vile,  Lemmy),  CRiSP,
   Emacs,  FTE (Folding Text Editor), JED, jEdit, Mined, NEdit (Nir-
   vana Edit), TSE (The SemWare Editor),  UltraEdit,  WorkSpace,  X2,
   Zeus

       Ctags  is  capable  of  generating different kinds of tags for each of
       many different languages. For a complete list of supported  languages,
       the  names  by  which they are recognized, and the kinds of tags which
       are generated for each, see  the  --list-languages  and --list-kinds
       options.

SOURCE FILES


       Unless  the --language-force option is specified, the language of each
       source file is automatically selected based upon a  mapping  of file
       names  to  languages.  The mappings in effect for each language may be
       display using the --list-maps option and may  be  changed  using  the
       --langmap  option.   On platforms  which support it, if the name of a
       file is not mapped to a language and the file is executable, the first
       line  of the file is checked to see if the file is a "#!" script for a
       recognized language.

       By default, all other files names are ignored.  This  permits  running
       ctags  on  all files in either a single directory (e.g. "ctags *"), or
       on all files in an entire source directory  tree (e.g. "ctags -R"),
       since  only  those  files  whose names are mapped to languages will be
       scanned.

       [The reason that .h extensions are mapped to C++ files rather  than  C
       files is because it is common to use .h extensions in C++, and no harm
       results in treating them as C++ files.]

OPTIONS


       Despite the wealth of available options, defaults  are set  so that
       ctags  is  most commonly executed without any options (e.g. "ctags *",
       or "ctags -R"), which will create a tag file in the current  directory
       for  all recognized source files. The options described below are pro-
       vided merely to allow custom tailoring to meet special needs.

       Note that spaces separating  the  single-letter options  from their
       parameters are optional.

       Note  also that the boolean parameters to the long form options (those
       beginning with "--" and that take  a  "[=yes|no]"  parameter)  may  be
       omitted, in  which case "=yes" is implied. (e.g. --sort is equivalent
       to --sort=yes). Note further that "=1" and "=on" are  considered syn-
       onyms for "=yes", and that "=0" and "=off" are considered synonyms for
       "=no".

       Some options are either ignored or useful only when used while running
       in etags mode (see -e option). Such options will be noted.

       Most  options  may appear anywhere on the command line, affecting only
       those files which follow the option.  A few  options,  however, must
       appear before the first file name and will be noted as such.

       Options taking language names will accept those names in either upper
       or lower case. See the --list-languages option for a complete list  of
       the built-in language names.

       -a   Equivalent to --append.

       -B   Use backward  searching  patterns (e.g. ?pattern?). [Ignored in
    etags mode]

       -e   Enable etags mode, which will create a tag file for use with  the
    Emacs  editor.  Alternatively, if ctags is invoked by a name con-
    taining the string "etags" (either by  renaming,  or  creating  a
    link to, the executable), etags mode will be enabled. This option
    must appear before the first file name.

       -f tagfile
    Use the name specified by tagfile for the tag  file (default  is
    "tags",  or "TAGS" when  running in etags mode). If tagfile is
    specified as "-", then the tag file is written to standard output
    instead.  Ctags  will stubbornly refuse to take orders if tagfile
    exists and its first line contains something other than  a valid
    tags line. This will save your neck if you mistakenly type "ctags
    -f *.c", which would otherwise overwrite your first C  file with
    the tags  generated by the rest! It will also refuse to accept a
    multi character file name which begins with a '-' (dash)  charac-
    ter,  since this most likely means that you left out the tag file
    name and this option tried to grab the next option as  the file
    name.  If  you  really want to name your output tag file "-ugly",
    specify it as "./-ugly". This option must appear before the first
    file  name. If this option is specified more than once, only the
    last will apply.

       -F   Use forward  searching  patterns  (e.g.  /pattern/)   (default).
    [Ignored in etags mode]

       -h list
    Specifies  a list of file extensions, separated by periods, which
    are to be interpreted as include (or header) files. To  indicate
    files  having  no  extension, use a period not followed by a non-
    period character (e.g.  ".",  "..x",  ".x.").  This option only
    affects  how  the scoping of a particular kinds of tags is inter-
    preted (i.e. whether or not they are considered as globally visi-
    ble or  visible only within the file in which they are defined);
    it does not map the extension to any particular language. Any tag
    which  is  located in a non-include file and cannot be seen (e.g.
    linked to) from another file is considered to  have file-limited
    (e.g.  static) scope. No kind of tag appearing in an include file
    will be considered to have file-limited scope. If the first char-
    acter in the list is a plus sign, then the extensions in the list
    will be appended to the current list; otherwise,  the  list will
    replace the current list. See, also, the --file-scope option. The
    default list is  ".h.H.hh.hpp.hxx.h++.inc.def".  To restore  the
    default  list, specify -h default. Note that if an extension sup-
    plied to this option is not already mapped to a  particular lan-
    guage (see SOURCE FILES, above), you will also need to use either
    the --langmap or --language-force option.

       -I identifier-list
    Specifies a list of identifiers which are to be specially handled
    while parsing C and C++ source files. This option is specifically
    provided to handle special cases arising through the use of pre-
    processor  macros. When the identifiers listed are simple identi-
    fiers, these identifiers will be ignored during  parsing  of  the
    source  files. If an identifier is suffixed with a '+' character,
    ctags will also ignore  any parenthesis-enclosed  argument list
    which  may immediately follow the identifier in the source files.
    If two identifiers are separated  with  the '='  character,  the
    first identifiers is replaced by the second identifiers for pars-
    ing purposes. The list of identifiers may be supplied directly on
    the command  line or read in from a separate file. If the first
    character of identifier-list is '@', '.' or a pathname  separator
    ('/'  or '\'), or the first two characters specify a drive letter
    (e.g. "C:"), the parameter identifier-list will be interpreted as
    a  filename from  which  to  read a list of identifiers, one per
    input line. Otherwise, identifier-list is a list  of  identifiers
    (or identifier pairs) to be specially handled, each delimited by
    a either a comma or by white space (in which case the list should
    be quoted to keep the entire list as one command line argument).
    Multiple -I options may be supplied.  To clear the list of ignore
    identifiers, supply a single dash ("-") for identifier-list.

    This  feature is useful when preprocessor macros are used in such
    a way that they cause syntactic confusion due to their  presence.
    Indeed,  this is the best way of working around a number of prob-
    lems caused by the presence of syntax-busting  macros  in  source
    files  (see BUGS, below). Some  examples will illustrate this
    point.

       int foo ARGDECL4(void *, ptr, long int, nbytes)

    In the above example, the macro "ARGDECL4" would  be  mistakenly
    interpreted to be the name of the function instead of the correct
    name of "foo". Specifying -I  ARGDECL4  results  in the  correct
    behavior.

       /* creates an RCS version string in module */
       MODULE_VERSION("$Revision: 1.35 $")

    In the  above example the macro invocation looks too much like a
    function definition because it is not  followed  by a  semicolon
    (indeed,  it  could even be followed by a global variable defini-
    tion that would look much like a  K&R  style  function  parameter
    declaration).  In  fact,  this  seeming function definition could
    possibly even cause the rest of the file to be skipped over while
    trying  to complete the definition. Specifying -I MODULE_VERSION+
    would avoid such a problem.

       CLASS Example {
   // your content here
       };

    The example above uses "CLASS"  as a  preprocessor macro which
    expands  to something  different for each platform. For instance
    CLASS may be defined as "class  __declspec(dllexport)"  on Win32
    platforms  and  simply "class" on UNIX.  Normally, the absence of
    the C++ keyword "class" would cause the source file to be  incor-
    rectly  parsed. Correct behavior can be restored by specifying -I
    CLASS=class.

       -L file
    Read from file a list of file names for which tags should be gen-
    erated.   If  file is specified as "-", then file names are read
    from standard input. File names read using this option  are pro-
    cessed  following  file  names  appearing  on  the command line.
    Options all also accepted in this input. If this option is speci-
    fied more than once, only the last will apply. Note: file is read
    in line-oriented mode, where a new line is the only delimiter and
    spaces  are considered significant, in order that file names con-
    taining spaces may be supplied; this can affect how options  are
    parsed if included in the input.

       -n   Equivalent to --excmd=number.

       -N   Equivalent to --excmd=pattern.

       -o tagfile
    Equivalent to -f tagfile.

       -R   Equivalent to --recurse.

       -u   Equivalent to --sort=no (i.e. "unsorted").

       -V   Equivalent to --verbose.

       -w   This  option  is silently ignored for backward-compatibility with
    the ctags of SVR4 Unix.

       -x   Print a tabular, human-readable cross reference  (xref)  file  to
    standard output instead of generating a tag file. The information
    contained in the output includes: the tag name; the kind of tag;
    the line  number, file  name, and source line (with extra white
    space condensed) of the file which defines the tag. No  tag file
    is written and  all  options  affecting tag file output will be
    ignored. Example applications for this feature are generating  a
    listing  of all functions located in a source file (e.g. ctags -x
    --c-kinds=f file), or generating a list of all externally visible
    global  variables  located in  a source file (e.g. ctags -x --c-
    kinds=v --file-scope=no file). This option must appear before the
    first file name.

       --append[=yes|no]
    Indicates  whether tags generated from the specified files should
    be appended to those already present in the tag  file  or  should
    replace  them.  This  option  is off by default. This option must
    appear before the first file name.

       --etags-include=file
    Include a reference to file in the tag file. This option  may  be
    specified as many times as desired. This supports Emacs' capabil-
    ity to use a tag file which "includes" other tag  files.  [Avail-
    able only in etags mode]

       --exclude=[pattern]
    Add pattern  to  a list of excluded files and directories. This
    option may be specified as many times as desired. For  each file
    name  considered  by  ctags,  each pattern specified using this
    option will be compared against  both  the complete  path (e.g.
    some/path/base.ext) and  the  base name  (e.g. base.ext) of the
    file, thus allowing patterns which match a given file name irre-
    spective of its path, or match only a specific path. If appropri-
    ate support is available from the runtime library of your C com-
    piler,  then  pattern  may contain the usual shell wildcards (not
    regular expressions) common on Unix (be sure to quote the  option
    parameter  to  protect  the wildcards from being expanded by the
    shell before being passed to ctags; also be aware that  wildcards
    can match the slash character, '/'). You can determine if shell
    wildcards are available on your platform by examining the  output
    of the  --version option, which will include "+wildcards" in the
    compiled feature list; otherwise, pattern is matched against file
    names using a simple textual comparison.

    If pattern begins with the character '@', then the rest of the
    string is interpreted as a file name from which to read exclusion
    patterns, one per line. If pattern is empty, the list of excluded
    patterns is cleared.  Note that at program startup, the  default
    exclude  list  contains "EIFGEN", "SCCS", "RCS", and "CVS", which
    are names of directories for which it is generally not  desirable
    to descend while processing the --recurse option.

       --excmd=type
    Determines the  type  of  EX  command used to locate tags in the
    source file.  [Ignored in etags mode]

    The valid values for type (either the entire word  or  the first
    letter is accepted) are:

    number   Use only line numbers in the tag file for locating tags.
     This has four advantages:
     1. Significantly reduces the size of the resulting  tag
file.
     2. Eliminates  failures  to  find tags because the line
defining the tag has changed, causing the  pattern
match to fail (note that some editors, such as vim,
are able to recover in many such instances).
     3. Eliminates finding identical  matching,  but  incor-
rect, source lines (see BUGS, below).
     4. Retains  separate  entries in the tag file for lines
which are identical in content.  In  pattern mode,
duplicate  entries  are  dropped  because the search
patterns they generate are  identical,  making  the
duplicate entries useless.

     However,  this  option  has  one  significant  drawback:
     changes to the source files can cause the line  numbers
     recorded  in the tag file to no longer correspond to the
     lines in the source file, causing jumps to some tags  to
     miss  the target definition by one or more lines. Basi-
     cally, this option is best used when the source code  to
     which  it is applied is not subject to change. Selecting
     this option type causes  the  following  options  to  be
     ignored: -BF.

    pattern  Use  only search patterns for all tags, rather than the
     line numbers usually used for  macro  definitions. This
     has  the advantage of not referencing obsolete line num-
     bers when lines have been added or removed since the tag
     file was generated.

    mixed    In this  mode,  patterns are generally used with a few
     exceptions. For C, line numbers are used for macro defi-
     nition  tags.  This  was the default format generated by
     the original ctags and is, therefore,  retained  as  the
     default  for  this option. For Fortran, line numbers are
     used  for common blocks because their corresponding
     source  lines  are generally  identical, making pattern
     searches useless for finding all matches.

       --extra=[+|-]flags
    Specifies whether to include extra tag entries for certain kinds
    of information. The parameter flags is a set of one-letter flags,
    each representing one kind of extra tag entry to include  in  the
    tag file. If flags is preceded by by either the '+' or '-' char-
    acter, the effect of each flag is  added  to,  or  removed from,
    those  currently enabled; otherwise the flags replace any current
    settings. The meaning of each flag is as follows:

       f   Include an entry for the base file name  of every  source
   file (e.g. "example.c"), which addresses the first line
   of the file.

       q   Include an extra class-qualified tag entry  for  each  tag
   which is a member of a class (for languages for which this
   information is  extracted; currently  C++, Eiffel,  and
   Java).  The actual form of the qualified tag depends upon
   the language from which the tag was derived (using a form
   that is most natural for how qualified calls are specified
   in the language). For C++, it is in the form "class::mem-
   ber";  for  Eiffel and Java, it is in the form "class.mem-
   ber". This may allow easier location of  a  specific tags
   when multiple  occurrences of a tag name occur in the tag
   file. Note, however, that this could potentially more than
   double the size of the tag file.

       --fields=[+|-]flags
    Specifies the available extension fields which are to be included
    in the entries of the tag file (see TAG FILE FORMAT,  below,  for
    more  information). The  parameter flags is a set of one-letter
    flags, each representing one type of extension field to  include,
    with  the  following  meanings  (disabled by default unless indi-
    cated):

       a   Access (or export) of class members
       f   File-restricted scoping [enabled]
       i   Inheritance information
       k   Kind of tag as a single letter [enabled]
       K   Kind of tag as full name
       l   Language of source file containing tag
       m   Implementation information
       n   Line number of tag definition
       s   Scope of tag definition [enabled]
       S   Signature of routine (e.g. prototype or parameter list)
       z   Include the "kind:" key in kind field

    Each letter or group of letters may be preceded by either '+'  to
    add it  to the default set, or '-' to exclude it. In the absence
    of any preceding '+' or '-' sign,  only  those  kinds  explicitly
    listed  in flags will be included in the output (i.e. overriding
    the default set). This option is ignored if the option --format=1
    has been specified. The default value of this options is fks.

       --file-scope[=yes|no]
    Indicates  whether tags scoped only for a single file (i.e. tags
    which cannot be seen outside  of  the  file in  which  they  are
    defined, such as "static" tags) should be included in the output.
    See, also, the -h option. This option is enabled by default.

       --filter[=yes|no]
    Causes ctags to behave as a filter, reading  source  file names
    from standard input and printing their tags to standard output on
    a file-by-file basis. If --sorted is  enabled,  tags  are  sorted
    only within the source file in which they are defined. File names
    are read from standard output in line-oriented  input  mode (see
    note  for -L option) and only after file names listed on the com-
    mand line or from any file supplied using  the  -L option. When
    this  option  is  enabled, the  options -f, -o, and --totals are
    ignored. This  option  is  quite  esoteric and  is disabled  by
    default. This option must appear before the first file name.

       --filter-terminator=string
    Specifies a string to print to standard output following the tags
    for each file name parsed when the --filter option is  enabled.
    This  may  permit  an  application reading the output of ctags to
    determine when the output for each file is finished. Note that if
    the file name read is a directory and --recurse is enabled, this
    string will be printed only one once at the end of all tags found
    for by descending the directory. This string will always be sepa-
    rated from the last tag line for the file by its terminating new-
    line.   This  option  is  quite esoteric and is empty by default.
    This option must appear before the first file name.

       --format=level
    Change the format of the output  tag  file. Currently  the only
    valid values for level are 1 or 2. Level 1 specifies the original
    tag file format and level 2 specifies a new extended format con-
    taining extension fields (but in a manner which retains backward-
    compatibility with original vi(1) implementations). The  default
    level  is  2. This option must appear before the first file name.
    [Ignored in etags mode]

       --help
    Prints to standard output a detailed usage description  and then
    exits.

       --if0[=yes|no]
    Indicates  a  preference  as  to  whether  code within an "#if 0"
    branch of a preprocessor conditional should be examined for non-
    macro  tags (macro tags are always included). Because the intent
    of this construct is to disable code, the default value  of this
    options  is no.  Note  that this indicates a preference only and
    does not guarantee skipping code within an "#if 0" branch, since
    the fall-back  algorithm used to generate tags when preprocessor
    conditionals are too complex follows all  branches of  a  condi-
    tional. This option is disabled by default.

       --<LANG>-kinds=[+|-]kinds
    Specifies a list of language-specific kinds of tags (or kinds) to
    include in the output  file for  a particular  language, where
    <LANG>  is case-insensitive  and is one of the built-in language
    names (see the --list-languages option for a complete list).  The
    parameter  kinds is a group of one-letter flags designating kinds
    of tags (particular to the language) to either include or exclude
    from  the  output. The specific sets of flags recognized for each
    language, their meanings and  defaults  may be  list  using  the
    --list-kinds  option. Each letter or group of letters may be pre-
    ceded by either '+' to add it to, or '-' to remove it  from,  the
    default  set.  In  the  absence of any preceding '+' or '-' sign,
    only those kinds explicitly listed in kinds will be included  in
    the output (i.e. overriding the default for the specified lan-
    guage).

    As an example for the C language, in order to add prototypes  and
    external  variable declarations to the default set of tag kinds,
    but exclude macros, use --c-kinds=+px-d; to include only tags for
    functions, use --c-kinds=f.

       --langdef=name
    Defines a new user-defined language, name, to be parsed with reg-
    ular expressions. Once defined, name may be used in other options
    taking language names. The typical use of this option is to first
    define the language, then map file names to it  using  --langmap,
    then  specify  regular expressions using --regex-<LANG> to define
    how its tags are found.

       --langmap=map[,map[...]]
    Controls how file names are mapped to languages (see the  --list-
    maps  option).  Each comma-separated map consists of the language
    name (either a built-in or user-defined language), a colon, and a
    list  of file extensions and/or file name patterns. A file exten-
    sion is specified by preceding the extension with a period (e.g.
    ".c").  A file name pattern is specified by enclosing the pattern
    in parentheses (e.g. "([Mm]akefile)"). If appropriate support  is
    available  from  the runtime library of your C compiler, then the
    file name pattern may contain the usual shell wildcards common on
    Unix  (be  sure  to quote the  option  parameter to protect the
    wildcards from being expanded by the shell before being passed to
    ctags).  You  can  determine  if shell wildcards are available on
    your platform by examining the output of  the  --version  option,
    which  will include  "+wildcards" in the compiled feature list;
    otherwise, the file name patterns are matched against file names
    using a simple textual comparison.

    If the  first character in a map is a plus sign, then the exten-
    sions and file name patterns in that map will be appended to  the
    current  map  for  that language; otherwise, the map will replace
    the current map. For example, to specify  that  only  files with
    extensions of  .c and .x are to be treated as C language files,
    use "--langmap=c:.c.x"; to also add files with extensions  of  .j
    as Java  language files, specify "--langmap=c:.c.x,java:+.j". To
    map makefiles (.e.g files named either "Makefile", "makefile", or
    having the extension ".mak") to a language called "make", specify
    "--langmap=make:([Mm]akefile).mak".   To  map  files  having   no
    extension, specify a period not followed by a non-period charac-
    ter (e.g. ".", "..x", ".x."). To clear the mapping for a particu-
    lar language  (thus  inhibiting automatic generation of tags for
    that  language),  specify an   empty   extension list (e.g.
    "--langmap=fortran:").  To restore the default language mappings
    for all a particular language, supply the keyword  "default"  for
    the mapping.   To specify restore the default language mappings
    for all languages, specify "--langmap=default".  Note  that file
    extensions are  tested  before file name patterns when inferring
    the language of a file.

       --language-force=language
    By default, ctags automatically selects the language of a  source
    file,  ignoring  those  files whose language cannot be determined
    (see SOURCE FILES, above). This option forces the specified lan-
    guage  (case-insensitive;  either built-in or user-defined) to be
    used for every supplied file instead of  automatically  selecting
    the language  based upon its extension. In addition, the special
    value auto indicates that the language  should  be automatically
    selected (which effectively disables this option).

       --languages=[+|-]list
    Specifies the languages for which tag generation is enabled, with
    list containing a comma-separated list of language names  (case-
    insensitive;  either built-in or user-defined). If the first lan-
    guage of list is not preceded by either a '+' or '-', the current
    list  will be cleared before adding or removing the languages in
    list. Until a '-' is encountered, each language in the list will
    be added  to the current list. As either the '+' or removed from
    the current list, respectively.  Thus,  it  becomes  simple  to
    replace the current list with a new one, or to add or remove lan-
    guages from the current list. The actual list of files for which
    tags  will be generated depends upon the language extension map-
    ping in effect (see the --langmap option). Note  that  all lan-
    guages,  including user-defined  languages are  enabled  unless
    explicitly disabled using this option. Language names included in
    list  may be any built-in language or one previously defined with
    --langdef. The default is "all", which  is also  accepted as  a
    valid  argument.  See  the --list-languages option for a complete
    list of the built-in language names.

       --license
    Prints a summary of the software license to standard  output  and
    then exits.

       --line-directives[=yes|no]
    Specifies  whether "#line" directives should be recognized. These
    are present in the output of preprocessors and contain  the line
    number,  and  possibly  the file  name,  of  the original source
    file(s) from which the preprocessor output file  was  generated.
    When  enabled,  this  option  will cause  ctags  to generate tag
    entries marked with the file names and  line  numbers  of their
    locations  original source file(s), instead of their actual loca-
    tions in the preprocessor output. The actual  file names  placed
    into  the  tag file will have the same leading path components as
    the preprocessor output file, since it is assumed that the origi-
    nal source files are located relative to the preprocessor output
    file (unless, of course, the #line directive specifies  an abso-
    lute  path).  This option is off by default. Note: This option is
    generally only useful when used together with the  --excmd=number
    (-n)  option.  Also,  you may have to use either the --langmap or
    --language-force option if the extension of the preprocessor out-
    put file is not known to ctags.

       --links[=yes|no]
    Indicates  whether symbolic  links (if supported) should be fol-
    lowed. When disabled, symbolic links are ignored. This option  is
    on by default.

       --list-kinds[=language|all]
    Lists  the tag kinds recognized for either the specified language
    or all languages. Each kind of tag recorded in the tag  file  is
    represented by  a one-letter flag, which is also used to filter
    the tags placed into the output through use of the --<LANG>-kinds
    option.  Note  that some languages and/or tag kinds may be imple-
    mented using regular expressions and  may  not  be available  if
    regex  support is not compiled into ctags (see the --regex-<LANG>
    option). Each kind listed is enabled unless followed by  "[off]".

       --list-maps[=language|all]
    Lists  the file extensions and file name patterns which associate
    a file name with a language for either the specified language  or
    all languages. See the --langmap option, and SOURCE FILES, above.

       --list-languages
    Lists the names of the languages understood by ctags. These lan-
    guage  names  are  case insensitive and may be used in the --lan-
    guage-force,  --languages, --<LANG>-kinds, and   --regex-<LANG>
    options.

       --options=file
    Read  additional  options  from  file.  As a  special  case,  if
    --options=NONE is specified as the first option  on the  command
    line,  it will disable the automatic reading of any configuration
    options from either a file or the environment (see FILES).

       --recurse[=yes|no]
    Recurse into directories encountered  in  the  list of  supplied
    files. If the list of supplied files is empty and no file list is
    specified with the -L option, then the  current  directory (i.e.
    ".")  is  assumed. Symbolic links are followed. If you don't like
    these behaviors, either explicitly specify the files or pipe  the
    output  of find(1) into ctags -L- instead. Note: This option is
    not supported on all platforms at present. It  is available  if
    the output of the --help option includes this option.  See, also,
    the --exclude to limit recursion.

       --regex-<LANG>=/regexp/replacement/[kind-spec/][flags]
    The /regexp/replacement/  pair  define  a regular   expression
    replacement pattern,  similar  in style to sed substitution com-
    mands, with which to generate tags from source  files  mapped  to
    the named language, <LANG>, (case-insensitive; either a built-in
    or user-defined  language).  The  regular expression,   regexp,
    defines  an extended  regular  expression (roughly that used by
    egrep(1)), which is used to locate a single source line  contain-
    ing a tag and may specify tab characters using \t. When a match-
    ing line is found, a tag will be generated for the name  defined
    by replacement,  which  generally will contain the special back-
    references \1 through \9  to  refer to  matching  sub-expression
    groups  within  regexp. The '/' separator characters shown in the
    parameter to the option can actually be replaced by any  charac-
    ter. Note that whichever separator character is used will have to
    be escaped with a backslash ('\') character wherever it  is used
    in the parameter as something other than a separator. The regular
    expression defined by this option is added to the current list of
    regular expressions for the specified language unless the parame-
    ter is omitted, in which case the current list is cleared.

    Unless modified by flags, regexp is  interpreted as  a Posix
    extended  regular  expression.  The replacement should expand for
    all matching lines to a non-empty  string  of  characters, or  a
    warning  message will be reported. An optional kind specifier for
    tags matching regexp may follow replacement, which will determine
    what  kind of tag is reported in the "kind" extension field (see
    TAG FILE FORMAT, below). The full form of  kind-spec  is  in  the
    form  of  a single letter,  a comma, a name (without spaces), a
    comma, a description, followed by a separator, which specify  the
    short  and long forms of the kind value and its textual descrip-
    tion (displayed using --list-kinds). Either the kind name  and/or
    the description  may  be  omitted. If  kind-spec is omitted, it
    defaults to "r,regex". Finally, flags are one or more single-let-
    ter characters  having the following effect upon the interpreta-
    tion of regexp:

       b   The pattern is  interpreted as  a Posix  basic  regular
   expression.

       e   The pattern is  interpreted  as a Posix extended regular
   expression (default).

       i   The regular expression is to be applied in a case-insensi-
   tive manner.

    Note  that this  option  is available only if ctags was compiled
    with support for regular expressions,  which  depends  upon your
    platform. You can determine if support for regular expressions is
    compiled in by examining the  output  of  the  --version  option,
    which will include "+regex" in the compiled feature list.

    For more  information  on the regular expressions used by ctags,
    see either the regex(5,7) man page, or the GNU info documentation
    for regex (e.g. "info regex").

       --sort[=yes|no|foldcase]
    Indicates  whether the tag file should be sorted on the tag name
    (default is yes). Note that the original  vi(1)  required  sorted
    tags.   The foldcase  value specifies case insensitive (or case-
    folded) sorting.  Fast binary searches of tag files sorted with
    case-folding  will require special support from tools using tag
    files, such as that found in the ctags readtags library,  or  Vim
    version  6.2 or higher (using "set ignorecase"). This option must
    appear before the first file name. [Ignored in etags mode]

       --tag-relative[=yes|no]
    Indicates that the file paths recorded in the tag file should  be
    relative  to  the  directory containing the tag file, rather than
    relative to the current directory, unless the files supplied  on
    the command  line are specified with absolute paths. This option
    must appear before the first file name. The default is  yes when
    running in etags mode (see the -e option), no otherwise.

       --totals[=yes|no]
    Prints  statistics about  the source files read and the tag file
    written during the current invocation of ctags.  This  option  is
    off by  default. This option must appear before the first file
    name.

       --verbose[=yes|no]
    Enable verbose mode. This prints out information on option pro-
    cessing and a brief message describing what action is being taken
    for each file considered by ctags. Normally, ctags does not read
    command line arguments until after options are read from the con-
    figuration files (see FILES, below) and  the  CTAGS  environment
    variable.  However, if  this option is the first argument on the
    command line, it will take effect before  any  options  are read
    from these sources. The default is no.

       --version
    Prints a version identifier for ctags to standard output and then
    exits.  This is guaranteed to always contain the string  "Exuber-
    ant Ctags".

OPERATIONAL DETAILS


       As  ctags  considers each file name in turn, it tries to determine the
       language of the file by applying the following three tests  in  order:
       if  the file extension has been mapped to a language, if the file name
       matches a shell pattern mapped to a language, and finally if the file
       is  executable  and  its first line specifies an interpreter using the
       Unix-style "#!" specification (if supported on  the  platform). If  a
       language was  identified, the file is opened and then the appropriate
       language parser is called to operate on the currently open  file.  The
       parser  parses  through the file and adds an entry to the tag file for
       each language object it is written to handle.  See  TAG FILE  FORMAT,
       below, for details on these entries.

       This  implementation  of ctags imposes no formatting requirements on C
       code as do legacy  implementations.  Older  implementations  of ctags
       tended to rely upon certain formatting assumptions in order to help it
       resolve coding dilemmas caused by preprocessor conditionals.

       In general, ctags tries to be  smart  about  conditional preprocessor
       directives.  If a  preprocessor conditional  is encountered within a
       statement which defines a tag, ctags follows only the first branch  of
       that conditional (except in the special case of "#if 0", in which case
       it follows only the last branch). The reason for this is that  failing
       to  pursue  only one branch can result in ambiguous syntax, as in the
       following example:

      #ifdef TWO_ALTERNATIVES
      struct {
      #else
      union {
      #endif
  short a;
  long b;
      }

       Both branches cannot be followed,  or  braces  become  unbalanced  and
       ctags would be unable to make sense of the syntax.

       If  the application of this heuristic fails to properly parse a file,
       generally due to complicated and inconsistent pairing within the con-
       ditionals, ctags will retry the file using a different heuristic which
       does not selectively follow  conditional preprocessor  branches,  but
       instead falls  back to relying upon a closing brace ("}") in column 1
       as indicating the end of a block once any brace imbalance results from
       following a #if conditional branch.

       Ctags  will  also  try to specially handle arguments lists enclosed in
       double sets of parentheses in order to  accept  the  following  condi-
       tional construct:

      extern void foo __ARGS((int one, char two));

       Any  name immediately preceding the "((" will be automatically ignored
       and the previous name will be used.

       C++ operator definitions are specially handled. In order for  consis-
       tency  with  all types of operators (overloaded and conversion), the
       operator name in the tag file will always be preceded  by  the  string
       "operator  "  (i.e. even if the actual operator definition was written
       as "operator<<").

       After creating or appending to the tag file, it is sorted by  the  tag
       name, removing identical tag lines.

TAG FILE FORMAT


       When not running in etags mode, each entry in the tag file consists of
       a separate line, each looking like this in the most general case:

tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields

       The fields and separators of these lines are specified as follows:

   1.  tag name
   2.  single tab character
   3.  name of the file in which the object associated with  the  tag
       is located
   4.  single tab character
   5.  EX command used to locate the tag within the file; generally a
       search pattern (either /pattern/ or ?pattern?) or line  number
       (see  --excmd). Tag file format 2 (see --format) extends this
       EX command under certain circumstances to  include  a  set  of
       extension  fields  (described below) embedded in an EX comment
       immediately appended to the EX command, which leaves it back-
       ward-compatible with original vi(1) implementations.

       A  few  special tags  are written into the tag file for internal pur-
       poses. These tags are composed in such a way that they always sort  to
       the  top of  the  file. Therefore, the first two characters of these
       tags are used a magic number to detect a tag  file  for purposes  of
       determining  whether a valid tag file is being overwritten rather than
       a source file.

       Note that the name of each source file will be  recorded in  the  tag
       file exactly as it appears on the command line. Therefore, if the path
       you specified on the command line was relative to the  current  direc-
       tory,  then  it will be recorded in that same manner in the tag file.
       See, however, the --tag-relative option for how this behavior  can  be
       modified.

       Extension fields are tab-separated key-value pairs appended to the end
       of the EX command as a comment, as described above.  These  key value
       pairs  appear  in  the general form "key:value". Their presence in the
       lines of the tag file are controlled by the --fields option. The pos-
       sible keys and the meaning of their values are as follows:

       access    Indicates the visibility of this class member, where value
   is specific to the language.

       file    Indicates that the tag has file-limited  visibility. This
   key has no corresponding value.

       kind    Indicates  the  type, or kind, of tag. Its value is either
   one of the corresponding one-letter flags described under
   the various --<LANG>-kinds options above, or a full name.
   It is permitted (and is, in fact, the default) for the key
   portion  of this field to be omitted. The optional behav-
   iors are controlled with the --fields option.

       implementation
   When present,  this indicates  a  limited  implementation
   (abstract vs. concrete) of a routine or class, where value
   is specific to the language ("virtual" or  "pure  virtual"
   for C++; "abstract" for Java).

       inherits    When present, value. is a comma-separated list of classes
   from which this class is derived (i.e. inherits from).

       signature   When present, value. is a  language-dependent  representa-
   tion of the signature of a routine. A routine signature in
   its complete form specifies the return type of  a  routine
   and its  formal  argument  list.  This extension field is
   presently supported only for C-based languages  and does
   not include the return type.

       In  addition,  information  on  the scope of the tag definition may be
       available, with the key portion equal to some language-dependent con-
       struct  name and its value the name declared for that construct in the
       program. This scope entry indicates the scope in which the  tag  was
       found.  For  example,  a tag generated for a C structure member would
       have a scope looking like "struct:myStruct".

HOW TO USE WITH VI


       Vi will, by default, expect a tag file by the name "tags" in the cur-
       rent  directory. Once  the  tag file is built, the following commands
       exercise the tag indexing feature:

       vi -t tag   Start vi and position the cursor  at the  file  and line
   where "tag" is defined.

       :ta tag    Find a tag.

       Ctrl-]    Find the tag under the cursor.

       Ctrl-T    Return to previous location before jump to tag (not widely
   implemented).

HOW TO USE WITH GNU EMACS


       Emacs will, by default, expect a tag file by the name  "TAGS"  in  the
       current directory. Once the tag file is built, the following commands
       exercise the tag indexing feature:

       M-x visit-tags-table <RET> FILE <RET>
Select the tag file, "FILE", to use.

       M-. [TAG] <RET>
Find the first definition of TAG. The default tag  is  the
identifier under the cursor.

       M-* Pop back to where you previously invoked "M-.".

       C-u M-. Find the next definition for the last tag.

       For more commands, see the Tags topic in the Emacs info document.

HOW TO USE WITH NEDIT


       NEdit  version 5.1 and later can handle the new extended tag file for-
       mat (see --format). To make NEdit use the tag file, select "File->Load
       Tags  File".  To jump to the definition for a tag, highlight the word,
       the press Ctrl-D. NEdit 5.1 can can read multiple tag files from dif-
       ferent  directories.  Setting the X resource nedit.tagFile to the name
       of a tag file instructs NEdit to automatically load that tag  file  at
       startup time.

CAVEATS


       Because ctags is neither a preprocessor nor a compiler, use of prepro-
       cessor macros can fool ctags into either missing tags  or  improperly
       generating  inappropriate  tags. Although  ctags has been designed to
       handle certain common cases, this  is  the  single  biggest  cause  of
       reported problems.  In particular, the use of preprocessor constructs
       which alter the textual syntax of C  can fool  ctags.  You  can work
       around many such problems by using the -I option.

       White  space is treated as a separator for file names and options read
       from list files, specified using the -L option, and  in filter mode
       (specified  using the --filter option). Therefore, it is not currently
       possible to supply file names or other options containing  embedded
       white space (spaces, etc.) through these options.

       Note  that  when ctags generates uses patterns for locating tags (see
       the --excmd option), it is entirely possible that the wrong  line  may
       be  found  by your editor if there exists another source line which is
       identical to the line containing the tag. The following example demon-
       strates this condition:

      int variable;

      /* ... */
      void foo(variable)
      int variable;
      {
  /* ... */
      }

       Depending  upon which editor you use and where in the code you happen
       to be, it is possible that the search pattern  may  locate  the local
       parameter declaration in foo() before it finds the actual global vari-
       able definition, since the lines (and therefore their search  patterns
       are identical). This can be avoided by use of the --excmd=n option.

BUGS


       Ctags has more options than ls(1).

       When  parsing a C++ member function definition (e.g. "className::func-
       tion"), ctags cannot determine whether the scope specifier is a class
       name  or a namespace specifier and always lists it as a class name in
       the scope portion of the extension fields. Also, if a C++ function  is
       defined outside of the class declaration (the usual case), the access
       specification (i.e. public, protected, or private) and  implementation
       information  (e.g.  virtual,  pure  virtual) contained in the function
       declaration are not known when the tag is generated for the  function
       definition.   It will, however be  available for  prototypes (e.g
       --c++-kinds=+p).

       No qualified tags are generated for language objects inherited into  a
       class.

ENVIRONMENT VARIABLES


       CTAGS   If  this environment  variable exists, it will be expected to
       contain a set of default options which  are  read  when ctags
       starts, after the configuration files listed in FILES, below,
       are read, but  before  any  command  line  options  are read.
       Options appearing  on  the command line will override options
       specified in this variable. Only options will  be  read from
       this  variable. Note that all white space in this variable in
       considered a separator, making it impossible to pass an option
       parameter  containing an embedded space. If this is a problem,
       use a configuration file instead.

       ETAGS   Similar to the CTAGS variable above, this variable, if  found,
       will be read when etags starts. If this variable is not found,
       etags will try to use CTAGS instead.

       TMPDIR  On Unix-like hosts where mkstemp() is available, the value  of
       this variable specifies the directory in which to place tempo-
       rary files. This can be useful if the size of a temporary file
       becomes too large to fit on the partition holding the default
       temporary directory defined at compilation time.   ctags cre-
       ates  temporary files  only  if either (1) an emacs-style tag
       file is being generated, (2) the tag file  is  being  sent  to
       standard output,  or  (3)  the program was compiled to use an
       internal sort algorithm to sort the tag files instead  of  the
       the  sort utility of the operating system. If the sort utility
       of the operating system is  being  used,  it  will  generally
       observe this variable also. Note that if ctags is setuid, the
       value of TMPDIR will be ignored.

FILES


       /ctags.cnf (on MSDOS, MSWindows only)
       /etc/ctags.conf
       /usr/local/etc/ctags.conf
       $HOME/.ctags ($HOME/ctags.cnf on MSDOS, MSWindows)
       .ctags (ctags.cnf on MSDOS, MSWindows)
      If any  of  these configuration files  exist,  each  will  be
      expected to contain a set of default options which are read in
      the order listed when ctags starts, but before the CTAGS envi-
      ronment  variable is read or any command line options are read.
      This makes  it  possible to  set up  site-wide, personal  or
      project-level defaults. It is possible to compile ctags to read
      an additional configuration file before any  of those shown
      above,  which  will  be indicated if the output produced by the
      --version option lists the  "custom-conf"  feature.  Options
      appearing in  the CTAGS environment variable or on the command
      line will override  options  specified  in  these files. Only
      options  will  be read  from these files. Note that the option
      files are read in line-oriented mode in which spaces  are sig-
      nificant (since shell  quoting is not possible). Each line of
      the file is read as one command line parameter (as if  it were
      quoted  with  single quotes). Therefore, use new lines to indi-
      cate separate command-line arguments.

       tags   The default tag file created by ctags.

       TAGS   The default tag file created by etags.

SEE ALSO


       The official Exuberant Ctags web site at:

      http://ctags.sourceforge.net

       Also ex(1), vi(1), elvis, or, better yet, vim, the official editor  of
       ctags. For more information on vim, see the VIM Pages web site at:

      http://www.vim.org/

AUTHOR


       Darren Hiebert <dhiebert@users.sourceforge.net>
       http://DarrenHiebert.com/

MOTIVATION


       "Think  ye  at  all times of rendering some service to every member of
       the human race."

       "All effort and exertion put forth by man from  the  fullness  of  his
       heart  is  worship,  if it is prompted by the highest motives and the
       will to do service to humanity."

      -- From the Baha'i Writings

CREDITS


       This version of ctags was originally derived from and inspired by  the
       ctags  program  by  Steve  Kirkendall <kirkenda@cs.pdx.edu> that comes
       with the Elvis vi clone (though virtually none of  the  original code
       remains).

       Credit  is  also due Bram Moolenaar <Bram@vim.org>, the author of vim,
       who has devoted so much of his time and energy both to developing  the
       editor as a service to others, and to helping the orphans of Uganda.

       The  section  entitled  "HOW  TO USE  WITH GNU EMACS" was shamelessly
       stolen from the info page for GNU etags.

'c or linux' 카테고리의 다른 글

POSIX 쓰레드로 멀티 쓰레드 프로그래밍하기  (0) 2005.02.18
함수 포인터  (0) 2005.02.16
ctags 활용  (0) 2005.02.15
#ifdef __cplusplus  (1) 2005.02.12
Setjmp()  (0) 2005.02.11
C언어 함수  (0) 2005.02.05
Posted by 김용환 '김용환'

댓글을 달아 주세요

[세마포어] [뮤텍스]

동기화에 필요한 기술들

데드락 걸렸을 때 사용하는 게 아니고 세마포어나 뮤텍스에 의해 데드락이 걸릴 수도 있습니다. 따라서 꼭 필요한 부분에만 제대로 사용해야합니다.


뮤텍스란 MUTual EXclusion으로 우리말로 해석하면 '상호 배제'라고 합니다. 말 그대로 상호 배제해서 실행하는 겁니다. 임계 구역을 가진 스레드들이 동시에 실행되지 않고 서로 배제되어 실행되게 하는 기술입니다. 여기서 임계구역(Critical Section)란 프로그램 상에서 동시에 실행될 경우 문제을 일으킬 수 있는 부분을 말합니다. 만약 어느 스레드에서 임계구역을 실행하고 있으면 다른 스레드들은 그 임계 구역에 접근할 수 없고 앞의 스레드가 임계 구역을 벗어나기를 기다려야합니다. 이런 방법이 뮤텍스입니다.

그리고 세마포어란 임계구역에 접근 하기 위한 열쇠 같은거라고 생각하면 됩니다. 예를 들어 화장실이 있다고 합시다. 이 화장실에 들어가기 위해서는 반드시 열쇠가 있어야 하고 이 열쇠는 단 하나 밖에 없으며 화장실에는 한명씩만 들어갈 수 있습니다. 이럴 때 여러명의 사람이 화장실을 이용하려면 일단 한명이 열쇠를 가지고 화장실을 이용하고 나오면 그 사람에게 열쇠를 받아 다음 사람이 이용하고 이렇게 한사람씩 돌아가면서 화장실을 쓸 수 있습니다. 이때 화장실은 임계구역이 되고 열쇠는 세마포어가 되는겁니다. 그리고 누군가 열쇠를 가지고 도망가버린다면 아무도 화장실을 사용하지 못하는 상태가 되어버립니다. 이런게 바로 데드락입니다. 데드락을 CPU 스케쥴링에서는 교착상태라고합니다.

 

세마포어(SEMAPHORE)

프로그래밍, 특히 유닉스시스템의 프로그래밍에서 세마포어는 운영체계의 자원을 경쟁적으로 사용하는 다중 프로세스에서, 행동을 조정하거나 또는 동기화 시키는 기술이다. 세마포어는 운영체계 또는 커널의 한 지정된 저장장치 내 값으로서, 각 프로세스는 이를 확인하고 변경할 수 있다. 확인되는 세마포어의 값에 따라, 그 프로세스가 즉시 자원을 사용할 수 있거나, 또는 이미 다른 프로세스에 의해 사용 중이라는 사실을 알게되면 재시도하기 전에 일정 시간을 기다려야만 한다. 세마포어는 이진수 (0 또는 1)를 사용하거나, 또는 추가적인 값을 가질 수도 있다. 세마포어를 사용하는 프로세스는 으레 그 값을 확인하고, 자원을 사용하는 동안에는 그 값을 변경함으로써 다른 세마포어 사용자들이 기다리도록 해야한다.

세마포어들은 일반적으로 메모리 공간을 공유하거나, 또는 파일들을 공유 액세스하기 위한, 두 가지 정도의 목적을 위해 사용된다. 세마포어들은 프로세스간 통신(IPC)을 위한 기술 중하나이다. C 프로그래밍 언어는 세마포어들을 관리하기 위한 일련의 인터페이스 또는 함수들을 제공한다.

이 세마포어를 가지고 경쟁관계에 있는 자원들을 충돌없이 잘 사용하기 위함입니다. 공유자원의 경우 다른 프로세스가 동시에 접근을 한다면, 어느 프로세스에 의해 변경된 자료가 나중에 수정된 자료인지 모르게 되는 문제가 생기며, 이로 인해 데이터의 각종 오류가 산재하게 됩니다. 그래서 세마포어 라는 일종의 변수를 두어 제어를 하게 됩니다.

 

세마포어

- 동기화의 일반적인 방법인 세마포어 방법은 세마포어라는 정수 변수(integer variable), 프로세스 대기열(process waiting queue), P와 V의 두 명령으로 구성된다. 초기 상태의 변수값은 자원의 수와 같으며 대기열은 비어 있다. P명령은 변수의 값을 하나 줄인 후, 변수의 값이 0보다 작으면 프로세스를 대기열로 집어 넣는다. 반대로 0보다 크면 그 프로세스는 계속 진행된다. V명령은 변수의 값을 하나 증가시킨다. 그 결과가 0보다 크면 프로세스는 계속되며 0보다 작으면 대기열의 프로세스 하나를 준비 상태로 만들고, 프로세스의 수행은 계속된다.  결국 변수의 값은 음수일 경우는 대기 중인 프로세스의 수를 나타내며, 양수이면 사용 가능한 자원의 수를 가리킨다. 위에서 동기화란 프로세스의 실행을 시간에 따라 순서적으로 처리하는 것을 동기화라 한다.

- 세마포어는 다익스트라(E.J.Dijkstra)가 제안한 동시에 정보를 공유하여 수행되는 두 개 이상의 프로그램이나 프로세스에서 활동 (activity)의 위치(coordination)를 설정해 주는 데 사용되는 동기화를 위한 기본 조작. 이는 두개 이상의 프로세스에 의해 공유되는 고유변수로 정의되는데, 보통의 방법으로는 다룰 수 없고 항상 P와 V라는 연산을 통해서만 액세스할 수 있다. 세마포어 sem이란 다음과 같은 연산이 허용된 정수형 변수를 말한다. (P와 V란 이름은 wait와 signal이란 말의 네덜란드어에서 나온것으로 이때 signal이란 물론 UNIX의 signal호출과는 다르다.) 두 연산은 모두 원자화되어야 한다. 즉 sem을 변경할수 있는 프로세스는 한 순간에 오직 하나 뿐이다.

 

컴퓨터가 여러 프로그램을 동시에 수행하는 다중 프로그래밍 시스템에서는 프로세스들간의 상호 배제와 동기화를 위한 기본적인 연산이 필요하다. 세마포어는 다익스트라가 제안한 프로세스 동기화를 위한 구조로, 이는 여러 프로세스들에 의해 공유되는 변수로 정의된다. 그런데 이 변수는 보통의 방법으로는 액세스할 수 없고 오직 P와 V라는 연산으로만 다룰 수 있다. P와 V연산의 정의는 다음과 같다. 

 

procedure P(S)   --> 최초 S값은 1임

    while S=0 do wait  --> S가 0면 1이 될때까지 기다려야 함

    S := S-1   --> S를 0로 만들어 다른 프로세스가 들어 오지 못하도록 함

end P

 

procedure V(S) --> 현재상태는 S가 0임

    S := S+1   --> S를 1로 원위치시켜 해제하는 과정. 이제는 다른 프로세스가 end V 들어 올수 있음

 

P와 V는 쪼갤수 없는 단일 연산이다. 즉 한 프로세스가 P나 V를 수행하고 있는 동안에는 프로세스가 인터럽트를 당하지 않는다. 이제 P와 V를 사용하면 다음과 같이 위험지역(cirtical section)에 대한 상호배제를 구현할수 있다. 

 

    P(S);

    -----------------
    | 위 험 지 역       |
    ----------------- 

    V(S);                                                                           |

최초에 S의 값은 1이다. 위와 같은 위험지역을 포함하는 두개의 프로세스 A와 B가 있다고 하자. A와 B는 서로 독립적으로 수행되지만, 두 프로세스가 동시에 위험 지역으로 들어가서는 안된다. 위와 같이 세마포어를 사용하면 P(S)를 먼저 수행하는 프로세스가 S를 0으로 해놓고 위험지역에 들어가므로 나중에 도착하는 프로세스는 P에서 더이상 진행되지 못하고 기다리게 된다. 먼저 들어갔던 프로세스가 V(S)를 해주어야 비로서 P(S)에서 기다리던 프로세스가 위험지역에 들어갈 수 있고 따라서 상호배제가  실현된다. 위의 예는 이진 세마포어 (binary semaphore)로, 단지 하나의 프로세스만이 위험지역에 들어갈 수 있도록 한다. 한편 S의 초기값을 N으로 하면 최대 N개의 프로세스가 P(S)를 통과할 수 있게 되는데 이러한 경우에는 계수 세마포어 (counting semaphore)라 하며 자원 할당에 사용한다. 

UNIX 시스템 V에서 구현된 세마포어는 이러한 개념에 기초했지만 보다 일반적인(그리고 아마도 보다 복잡한)기능을 제공한다. 

우선 semget과 semctl을 살펴보자.

        <사용법>
         #include
         #include
         #include
   
         key_t key;
         int sem_id, nsems, permflags, command;
         int retval, sem_num;
         union semun

         {
               int val;
               struct semid_ds *stat;
               ushort *array;
          } ctl_arg;
                .
                .
                .
         sem_id = semget(key, nsems, perflags);
         retval = semctl(sem_id, sem_num, command, ctl_arg);

 

semget 호출은 msgget(get message queue)과 유사하다. 인수 nsems는 세마포어 집합에 필요한 세마포어의 갯수를 나타낸다. 따라서 UNIX 세마포어 연산은 세마포어 하나만이 아니라 한 집합 전체를 다루게 된다. 이로 인해서 나머지 세마포어 루틴에 대한 인터페이스가 복잡해진다. semget호출이 성공하면 세마포어 집합 식별자라는 메시지 큐 식별자와 유사한 역할을 하는 것이 돌아온다. C 언어의 관습을 따라서 세마포어 집합에 대한 첨자는 0부터 nsems-1까지 있을 수 있다. 집합 내의 각 세마포어는 다음과 같은 값들을 갖게 된다. 

       . semval : 세마포어의 값으로서 항상 양수가 지정된다.
                  여기에 값을 새로 지정하려면 반드시 세마포어 시스템 호출을 통해야하며 프로그램에서 일반 자료형의 변수와 같이 직접
                  접근 할 수는 없다.
       . sempid : 세마포어에 접근했던 최근의 프로세스의 프로세스 식별번호이다.
       . semncnt : 세마포어의 값이 현재보다 증가하기를 기다리는 프로세스의 갯수
       . semzcnt : 세마포어의 값이 0으로 되기까지 기다리는 프로세스의 갯수


정의에서 알 수 있듯이 함수 semctl은 msgctl보다 훨씬 복잡하다. sem_id는 유효한 세마포어 식별자라야 한다. command는 msgctl에서와 같이 수행해야 할 정확한 기능을 명시한다. 이 기능에는 세가지 유형이 있다. IPC_STAT와 같은 표준 IPC기능, 단일 세마포어만을 다루는 기능, 세마포어의 전체를 다루는 기능이 그것이다. 

 

가능한 모든 기능을 다음과 같이 정리하였다.
                   
                   semctl(semaphore control operations) 기능 코드
   -----------------------------------------------------------------------------
         표준 IPC기능 (semid_ds구조는 sem.h에 정의되어 있다.)
   -----------------------------------------------------------------------------
         IPC_STAT  상태정보를 ctl_arg.stat에 저장한다.
         IPC_SET   ctl_arg.stat에 저장된 형태로 소유권과 사용 허가권을 지정한다.
         IPC_RMID  시스템에서 해당 세마포어의 집합을 삭제한다.
   -----------------------------------------------------------------------------
         단일 세마포어 연산 (이들은 retval에게 넘어온 값 sem_unm을 사용한다.)
   -----------------------------------------------------------------------------
         GETVAL    세마포어의 값 semval을 돌려준다.
         SETVAL    세마포어 값을 ctl_arg.val로 지정한다.
         GETPID    sempid의 값을 돌려준다.
         GETNCNT   semncnt를 돌려준다.
         GETZCNT   semzcnt를 돌려준다.
   -----------------------------------------------------------------------------
         전체 세마포어 연산
   -----------------------------------------------------------------------------
         GETALL    모든 senvals의 값을 ctl_arg.array에 저장한다.
         SETALL    ctl_arg.array의 값을 사용하여 모든 semvals값을 지정한다.
   ----------------------------------------------------------------------------- 
   
sem_num 인수는 semctl의 단일 세마포어 기능에서 특정 세마포어를 지정해준다. 마지막 인수인 ctl_arg는 세가지 구성 요소의 결합이다. 이들 구성 요소들은 각각 semctl의 세가지 기능에 대응한다. semctl은 세마포어의 초기값을 지정할 때 요긴하게 사용된다. 이 기능은 semget에는 없음에 주의하라. 따라서 semget과 semctl은 두개 모두 있어야 한다. 다음에 예로서 제시하는 함수는 프로그램이 단일 세마포어를 생성할때나 이에 대한 세마포어 집합 식별자를 얻고자 할 때 사용될 수 있다. 세마포어가 생성되는 경우에는 semctl을 사용하여 초기값을 부여하게 된다.

 

   /* initsem  -- semaphore initialization */
    #include "pv.h"
   

    initsem(semkey)   

    key_t semkey;
    {
          int status = 0, semid ;
          if ((semid = semget(semkey, 1, SEMPERM|IPC_CREAT|IPC_EXCL)) == -1)

          {
               if (errno == EEXIST)
                   semid = semget(semkey, 1, 0);
          }

          else   /* if created... */
               status = semctl(semid, 0, SETVAL, 1);

        if ((semid == -1 || status == -1)

        {
             perror("initsem failed");
             return (-1);
        }

        else
             return semid;    /* all okay  */
     }

 

  include 화일 pv.h는 다음과 같다.

    /* semaphore example header file */
    #include
    #include
    #include
    #include

    extern int errno;

    #define SEMPERM 0600
    #define TRUE 1
    #define FALSE 0

 

세마포어 연산 : semop 호출
semop은 기본적인 세마포어 연산을 실제로 수행하는 시스템호출이다. 이때 semop은 메뉴얼의 항목이 아니라 실제 함수 이름이다.


   사용법
      #include
      #include
      #include
      int retval, sem_id;
      struct sembuf op_array[SOMEVALUE];
               .
               .
      retval = semop(sem_id, op_array, SOMEVALUE);

 

sem_id는 세마포어 집합 식별자로서 이전에 semget호출을 통해 값이 지정되어야 한다. op_array는 sembuf구조의 배열로서 sembuf구조는 sem.h에 정의되어 있다. SOMEVALUE는 임의의 정수형 상수이다. 각각의 sembuf구조 변수는 세마포어에 대해 수행할 연산을 지정한다. 다시 강조하거니와 semop함수가 세마포어 집합에 대해 수행하는 일련의 연산들은 모두 원자화 되어야 한다. 즉, 그중의 한 연산이라도 수행할 수 없다면 전체 연산이 모두 수행되지 말아야 한다. 이 경우에는 특별히 명시되지 않는 한, 모든 연산이 한번에 수행될수 있을때까지 프로세스의 수행이 중지된다. sembuf구조를 좀더 자세히 보면 다음과 같이 구성되어 있다.
 
      --------------------------------------------------------------------
      |     struct sembuf {                                                                         |
      |     short   sem_num;        /* semaphore # */                                    |
      |     short   sem_op;         /* semaphore operation */                          |
      |     short   sem_flg;        /* operation flags */                                    |

      |     }                                                                                             |
      --------------------------------------------------------------------

 

sem_num는 집합 내의 세마포어에 대한 첨자를 저장한다. 만약 집합의 원소가 하나뿐이라면 sem_num의 값은 0이어야 한다.  sem_op는 함수 semop이 수행해야 하는 기능을 정수로서 나타낸다. 

여기에는 세가지 경우가 있다.

 

경우 1 : sem_op가 음수일때

이 경우에는 앞서 소개했듯이 일반적인 세마포어 명령 P()와 같이 수행된다. 이를 의사 코드(pseudo-code)로 나타내면 다음과 같다.(ABS는 변수의 절대값을 나타낸다)

 

        if (semval >= ABS(sem_op))

        {
             set semval to semval-ABS(sem_op)
        }

        else

        {
             if ((sem_flg&IPC_NOWAIT))
                     return-1 immediately
             else

             {
                    wait until semval reaches or exceeds
                    ABS(sem_op), then subtract
                    ABS(sem_op) as above
              }
        }

기본 개념은 함수 semop에서 sem_num이 가리키는 세마포어의 값 semval을 조사하는 것이다. semval의 값이 충분히 크다면 즉시 하나 감소시킨다. 아니면 semval이 충분히 커질 때까지 프로세스의 수행을 중단시킨다. 그러나 sem_flg의 IPC_NOWAIT 플래그의 값이 1로 되어 있으면 sem_op은 즉시 -1을 되돌려주고 errono값을 EAGAIN으로 한다.

 

경우 2 : sem_op이 양수일 때

이때는 보통의 V()연산과 유사하다. 즉 sem_op의 값을 해당 semval에 더해준다. 이때 해당 세마포어의 값이 증가하기를 기다리는 프로세스들이 깨어나게 된다.
   
경우 3 : sem_op이 0일때

이 경우는 semval을 변환시키는 것이 아니라 값이 0이 될때까지 기다린다. semval이 0이 아니고 sem_flg의 IPC_NOWAIT가 1인 경우에 semop는 즉시 오류 값을 돌려주게 된다.
        
SEM_UNDO 플래그

이것은 sembuf구조의 구성요소 sem_flg에 있는 플래그의 하나이다. 이는 프로세스의 수행이 끝났을 때 시스템이 수행된 연산을 자동적으로 취소하도록 지시한다. 수행된 일련의 연산을 추적하기 위하여 시스템은 세마포어에 semadj라는 정수를 대응시킨다. 이때 semadj변수는 프로세스마다 할당되어야 함에 주의해라. 따라서 서로 다른 프로세서는 동일한 세마포어에 대해 독립적인 semadj값을 유지하게 된다. SEM_UNDO의 값을 1로 하고서 semop연산을 수행하면 semadj값에서 sem_num값을 뺀다. 이때 sem_num의 부호가 중요한데 이는 sem_num의 값이 양수인가 음수인가에 따라 semadj의 값이 감소하거나 증가하기 때문이다. 프로세스의 수행이 끝나면 시스템은 semadj값을 해당 세마포어에 더해줌으로써 지금까지의 모든 semop호출 효과를 상쇄시킨다. 일반적으로 볼때 프로세스가 지정한 값이  해당 프로세스의 종료 후에도 효력을 갖지 않는다면 SEM_UNDO가 사용되어야만 한다.

 

세마포어의 예

이제 initsem루틴으로 시작한 예를 완성해 보자. 여기서는 전통적인 세마포어 연산을 P()와 V()로 구현하여 이를 중심으로 삼았다. 우선 P()를 보자.

       /* pc -- semaphore p operation */
       #include "pv.h"
       p(semid)
       int semid;
       {
           struct sembuf p_buf;
           p_buf.sem_num = 0;
           p_buf.sem_op = -1;
           p_buf.sem_flg = SEM_UNDO;
         
           if (semop(semid, &p_buf, 1) == -1)

           {
               perror("p(semid) failed");
               exit(1);
           }

           else
               return(0);
        }

 

이때 SEM_UNDO를 사용했음에 주의하라. V()는 다음과 같다.
     
        /* v.c -- semaphore v operation */
        #include "pv.h"
        v(semid)
        int semid;
        {
            struct sembuf v_buf;
            v_buf.sem_num = 0;
            v_buf.sem_op = 1;
            v_buf.sem_flg = SEM_UNDO;
 
            if(semop(semid, &v_buf, 1) == -1)

            {
                perror("v(semid) failed");
                exit(1);
            }

            else
                return(0);
         }

 

이제 비교적 간단한 이들 루틴으로 상호 배제를 구현해보자. 다음의 프로그램을 살펴보자.

 

         /* testsem -- test semaphore routines */
         #include "pv.h"
        
         main()
         {
              key_t semkey = 0x200;
             
              if(fork() == 0)
                 handlesem(semkey);

              if(fork() == 0)
                 handlesem(semkey);

              if(fork() == 0)
                 handlesem(semkey);
          }
            
          handlesem(skey)
          key_t skey;
          {
              int semid, pid = getpid();

              if((semid = initsem(skey)) < 0)
                  exit(1);
              printf("\nprocess %d before critical section\n", pid);
       
              p(semid);
              printf("process %d in critical section\n", pid);
            
              /* in real life do something interesting */
              sleep(10);
              printf("process %d leaving critical section\n", pid);

              v(semid);
              printf("process %d exiting\n", pid);
              exit(0);
           }

testsem은 세개의 자식프로세스를 생성하고 , 이들은 p()와 v()를 사용하여 임계 영역에는 한 순간에 둘 이상이 들어있지 못하도록 한다. 한 컴퓨터에서 testsem을 수행시킨 결과는 다음과 같다.

 

              process 799 before critical section
              process 800 before critical section
              process 801 before critical section

              process 799 in critical section
              process 799 leaving critical section
              process 799 exiting
              process 801 in critical section
              process 801 leaving critical section
              process 801 exiting
              process 800 in critical section
              process 800 leaving critical section
              process 800 exiting

 

o Critical secion 란 ?

다중 프로그래밍 운영체제에서 여러 프로세스가 데이타를 공유하면서 수행될 때 각 프로세스에서 공유 데이타를 액세스하는 프로그램 코드 부분을 가리키는 말. 공유데이타를 여러 프로세스가 동시에 액세스하면 시간적인 차이 때문에 잘못된 결과를 만들어 낼 수 있기 때문에 한 프로세스가 위험 부분을 수행하고 있을 때, 즉 공유 데이타를 액세스하고 있을 때는 다른 프로세스들은 절대로 그 데이타를 액세스하지 못하도록 하여야 한다.

o Mutual exclusion (상호 배제)란(1) ?

- 프로세스의 상호 교신에 대한 기본적인 조치는 공용 부분을 여러 프로세스가 동시에 사용하는 것을 배제하는 것이었다. 시스템의 어떠한 자원을 한 시점에서 한개의 프로세스만이 사용할 수 있도록 하는 것을 상호배제라 한다. 또한, 프로그램에서 이러한 자원을 사용하거나 혹은 그 내용을 변경하는 부분을 위험부분 (critical section)이라 하며, 둘 이상의 프로그램에서 이 위험 부분이 동시에 수행되지 않도록 하는 것이 상호 배제의 기능이다. 

- 다중 프로그래밍 시스템에서 여러 프로세스가 하나의 공유 데이타를 액세스하면서 작업을 할 때, 한 프로세스가 그 데이타를 액세스할 때는 다른 프로세스들은 그것을 사용하지 못하도록 하는 운영체제의 기능. 예를 들어 한 프로세스가 어떤 화일에 데이타를 쓰고 있을 때 다른 프로세스가 그 화일을 지원버린다면 많은 문제가 발생할 것이다. 상호 배제는 한번에 한 프로세스만이 공유 데이타를 액세스할 수 있도록 해 주는 것으로, 다중프로그래밍 시스템의 운영체제가 꼭 갖추어야 할 기능이다.

Posted by 김용환 '김용환'

댓글을 달아 주세요

#ifdef __cplusplus

c or linux 2005. 2. 12. 20:39


#ifdef __cplusplus
extern "C" {
#endif

C++파일이면 extern "C" { 이 구문을 추가하라는 얘깁니다.
이 헤더파일이 C++에서 사용될 경우 C 파일에서 정의된 함수는 C++에서
사용할 수 없기 때문에 미리 정의해놓은 것이지요..

#ifdef __cplusplus
extern "C"
{
#endif

C함수 선언들...

#ifdef __cplusplus
}
#endif

 

 

전처리기에서 가장 먼저 수행 되는 부분 입니다. 선행처리기라고도 합니다. 종류로는 #define, #if, #ifdef, #ifndef, #defined, #undef가 있습니다. 이것은 기존에 있는 방대한 소스 코드를 지우지 않고 활성화 비활성화 하는데 가장 많이 이용 합니다. 기존에 있는 소스를 건드리지 않는 상태에서 부분적으로 컴파일 하는곳에 쓰입니다.

 

#define

구문의 상수로 치환할때 쓰입니다. 대체해서 쓰겠다는 뜻입니다.

또한 #define은 함수 역활 비슷하게 매크로로써 쓰일수 있습니다.

#define SUM(x) ((x) = (x)+(x))

이렇게 쓰일수 있습니다. 동작원리는 함수와 같습니다. 말 그대로 main소스에서 SUM을 호출하면 옆에 있는 더하기 코드가 치환되는 것입니다.

 

#ifdef, #ifndef

(#ifndef __헤더명_H__)

헤더파일이 겹치는 것을 막기위한 일종의 매크로입니다. 예를들어 헤더파일에다가 어떤 클래스의 인터페이스 선언을 넣었다고 합시다. 이 클래스 인터페이스에서 다른 파일의 프로토타잎이 필요해서 다른 A 파일을 include 하고 있는데 이 헤더 파일을 include 하는 파일에서 A라는 헤더 파일을 이미 include 하고 있다면 두번 define한 것이 됩니다. 그러면 SYNTEX 에러가 나겠지요. 그래서 그런것을 막는 방법의 하나로 #ifndef을 제공합니다. 이전에 include되어 있으면 #endif쪽으로 점프해버려 결국 한번 선언되는 것입니다.

예를 들어

#include  <stdio.h>    ------ (a)

#include  <stdio.h>    ------ (b)
두번 썼다고 합시다. 그런데 앞에 이미 include를 했는데 밑에 또 한다면 문제가 되겠죠. 컴파일러가 검사해야할 코드량도 많아지구요.

그래서 stdio.h 에는

#ifndef _STDIO_H

#define _STDIO_H

가 선언되어 있습니다.

만약 _STDIO_H가 선언되어 있지 않다면 선언한다는 뜻이죠. 그 뒤 (b)에서는 이미 (a) 쪽에서 _STDIO_H 을 선언한 상태이기 때문에 전처리기 쪽에서 무시해버립니다. 그럼 컴파일러는 (a)만 검사하겠죠.


컴파일할 때

#ifdef HAHAHAHA

               printf("HAHAHAHA");

#else

               printf("HOHOHOHO");

#endif

와 같이 쓰면 만약 HAHAHAHA가 선언되어 있다면 printf("HAHAHAHA");를 전처리기가 컴파일러에게 넘겨주고 아니라면 printf("HOHOHOHO"); 를 넘겨줍니다. 컴파일할 때 전처리기에게 옵션을 줄 수 있습니다. 이것을 보통 preprocessor definition 이라고 하는데요, 전처리기에게 "HAHAHAHA가 있는 부분을 포함시켜!" 라고 옵션을 주는 것이죠. 보통 컴파일러마다 제공합니다. 비주얼 스투디오도 셋팅에 보면 있구요, gcc는 gcc -DHAHAHAHA .......... 와 같이 하면 되죠.

 

#if

#if 구문은 if랑 아주 비슷합니다.

이것은 어떠한 구문을 컴파일 할지 안할지를 지정할수 있습니다.
#define A 1
#if A
    source code.....
#endif
위에는 소스는 컴파일이 됩니다. if문에서와 같이 참, 거짓을 구분하여 컴파일 됩니다. 위에서 A값은 1...즉 0보다 큰수 이기 때문에 참으로 돌아가는 것입니다. 직접 #if 0 .... #endif 이렇게 하면 거짓이기 때문에 이 부분은 컴파일이 되지 않습니다.

 

#defined

여러개의 define이 되어져 있는지를 검사할때 쓰입니다. 이것은 여러개를 동시에 검사 할수 있습니다.

#if #defined A || #defined B

 

#undef

위에서 define된 것을 무효화 시키는 것입니다. 예를 들면

#define A 10

이렇게 되있고 뒤에서

#undef A

이렇게 하면 A로 디파인된 값은 무효화 되는 것입니다.

 

 

프로그래머들 마다의 코딩 스타일(암시적 약속)이 있습니다. 보통 매크로, const 변수는 대문자로 적는 것이 원칙입니다. 매크로 함수와 일반함수, 매크로대상체(object-like macro)와 일반변수를 구분하기 쉽게 해주는 것이지요.

#define STDIO_H_

왜 뒤에 _를 붙였을까요? 이것도 하나의 암시적 약속입니다. 컴파일러 제작회사는 매크로를 정의할 때 사용자들과 이름이 충돌이 나지 않게 하기 위해서 대부분 _를 뒤어 덧붙입니다. 또한 _를 하나 혹은 두개연속으로 시작하는 것은 컴파일러 내부에서 사용하는 매크로라는 성격이 강합니다. 물론 강제적인 뜻은 없으며 단지 관습상 그렇습니다. 왜 이것이 관습이 되었나하면 보통 매크로 변수이름이나 함수이름을 지을때 뒤에 _를 붙이지 않기 때문입니다. 그래서 함수제작자들이 _를 단골로 붙였습니다.

 

다음과 같은 매크로는 컴파일러 내부에서 실제로 쓰이며 표준 C에서 인정한 매크로들 입니다. 설마 사용자가 이런 매크로를 정의해서 사용하지는 않겠죠? 물론 다시 정의하면 오류가 나게 됩니다.

__LINE__

__FILE__

__DATE__

__IME__

__STDC__

__STDC

_VERSION__

printf("%d\n", __LINE__); 과 같이 실제로 찍어볼 수도 있습니다.

 

사실 매크로명은 마음대로 지어도 상관없습니다. 하지만 경력이 많은 C 프로그래머들이 암시적으로 써온 약속들이 있기 때문에 대부분 그렇게 하는 것입니다. 내부적으로 해석되는 것은 토큰이 하나 이상만 되면 모두 매크로 정의가 되는 것이며 하나일 경우 치환은 되지 않습니다.

 

 

C의 predefined macro

__FILE__ a string that holds the path/name of the compiled file
__LINE__ an integer that holds the number of the current line number
__DATE__ a string that holds the current system date
__TIME__ a string that holds the current system time
__STDC__ defined as the value '1' if the compiler conforms with the ANSI C standard
__cplusplus determines if your compiler is in C or C++ mode. Usually used in headers

 

예)

#include <stdio.h> 
 
void main(void) 

    printf("The path/name of this file is %s\n", __FILE__); 
    printf("The current line is %d\n", __LINE__); 
    printf("The current system date is %s\n", __DATE__); 
    printf("The current system time is %s\n", __TIME__);  

    #ifdef __STDC__ 
        printf("The compiler conforms with the ANSI C standard\n"); 
    #else 
        printf("The compiler doesn't conform with the ANSI C standard\n"); 
    #endif 
    #ifdef __cplusplus 
        printf("The compiler is working with C++\n"); 
    #else 
        printf("The compiler is working with C\n"); 
    #endif 

 


 

'c or linux' 카테고리의 다른 글

POSIX 쓰레드로 멀티 쓰레드 프로그래밍하기  (0) 2005.02.18
함수 포인터  (0) 2005.02.16
ctags 활용  (0) 2005.02.15
#ifdef __cplusplus  (1) 2005.02.12
Setjmp()  (0) 2005.02.11
C언어 함수  (0) 2005.02.05
Posted by 김용환 '김용환'

댓글을 달아 주세요

  1. 안아론 2012.03.20 15:07  댓글주소  수정/삭제  댓글쓰기

    정말 유익한정보를 알기쉽게 써주셧네요ㅎㅎ 많이배우고갑니다!

www.eclipse-plugins.info

Top rated


pages: 1 2 3 Next>
    Plugin   avg. rating   # ratings
1 Hibernate Synchronizer 8.8 48
2 VSS Plugin for Eclipse 8.7 55
3 XMLBuddy 8.5 89
4 SWT/Swing Designer 8.5 43
5 JLint 8.5 4
6 Persistence for Eclipse 8.5 4
7 JasperAssistant 8.5 22
8 SQLExplorer 8.5 18
9 Sysdeo Eclipse Tomcat Launcher 8.4 64
10 JadClipse 8.4 13
11 EclipseColorer 8.4 11
12 Jalopy 8.4 13
13 EclipseProfiler 8.4 25
14 QuantumDB 8.4 18
15 ColorEditor 8.4 7
16 EditorList 8.4 5
17 Call Hierarchy View 8.4 11
18 Implementors 8.4 12
19 Checkclipse 8.4 11
20 W4T Eclipse 8.4 9
21 RMI Plugin for Eclipse 8.4 5
22 Regular Expression Tester 8.4 23
23 Exadel Struts Studio 8.4 16
24 DBEdit 8.4 16
25 PriDE Entity Generator 8.4 5
26 Jigloo SWT/Swing GUI Builder 8.4 16
27 Log4E 8.4 14
28 AnyEdit tools 8.3 6
29 eclipsetidy 8.3 3
30 EMF (Eclipse Modeling Framework) 8.3 6
31 MyEclipse Enterprise Workbench 8.3 49
32 EPIC - Eclipse Perl Integration 8.3 10
33 Oxygen - XML editor 8.3 6
34 SDE for Eclipse 8.3 3
35 NitroX 8.3 6
36 Eclipse-games 8.2 4
37 ToString generator 8.2 4
38 Eiffel for Eclipse (EfE) 8.2 5
39 PMD For Eclipse 8.1 7
40 Metrics 8.1 9
pages: 1 2 3 Next>
note: plugins need to have received at least three ratings to be listed.
 
 

'java UI' 카테고리의 다른 글

File Connection Optiobal Package  (0) 2006.02.28
[펌] DataSource의 복제를 통한 다중 플레이어 생성방법  (0) 2005.12.02
jtable tutorial  (0) 2005.02.16
The Eclipse runtime options  (0) 2005.02.15
www.eclipse-plugins.info 의 순위  (0) 2005.02.12
BEYOND THE BASICS OF JOPTIONPANE  (0) 2005.02.11
Posted by 김용환 '김용환'

댓글을 달아 주세요

Threads from aritma

java core 2005. 2. 12. 08:15
 
From
 
Objects and Java Seminar by Bill Venners
Threads
Lecture Handout

Agenda

  • Introduce multi-threading
  • Show two ways to start a thread
  • Talk about synchronization for mutual exclusion
  • Discuss thread cooperation
  • Look at the Java monitor
  • Look at thread blocking, liveness, and scheduling

Multi-Threading in Java

  • Java has support for multi-threading built into the language
  • Threads are "sub-processes" within a process
    • User-interface responsiveness
    • Server responsiveness
    • Can take advantage of multi-processors
  • Each process has a private data segment. Threads share the data segment of their process.
  • Two kinds of synchronization: mutual exclusion and co-operation

Subclassing Thread

  • In Java, threads are represented by an instance of class java.lang.Thread
  • Two ways to define a thread starting point: extend Thread or implementing Runnable

     1 // In file threads/ex1/RepetitiveThread.java
     2 public class RepetitiveThread extends Thread {
     3
     4     private final String msg;
     5     private final long sleepTime;
     6
     7     public RepetitiveThread(String msg, long sleepTime) {
     8         this.msg = msg;
     9         this.sleepTime = sleepTime;
    10     }
    11
    12     public void run() {
    13
    14         for (;;) {
    15
    16             System.out.println(msg);
    17             try {
    18                 sleep(sleepTime);
    19             }
    20             catch (InterruptedException e) {
    21             }
    22         }
    23     }
    24 }
    
     1 // In file threads/ex1/Example1.java
     2 public class Example1 {
     3
     4     // Args to this application specify "msg"
     5     // and "sleepTime" for multiple threads.
     6     // For example, the command:
     7     //
     8     // $ java Example1 Hi 100 Lo 1000
     9     //
    10     // requests two threads, one that prints
    11     // out "Hi" every 100 milliseconds and
    12     // another that prints out "Lo" every
    13     // 1000 milliseconds.
    14     //
    15     public static void main(String[] args) {
    16
    17         // Require an even argCount
    18         int argCount = args.length;
    19         if ((argCount / 2) == 1) {
    20             --argCount;
    21         }
    22
    23         for (int i = 0; i < argCount; i += 2) {
    24
    25             String msg = args[i];
    26             long sleepTime = Long.parseLong(args[i + 1]);
    27
    28             RepetitiveThread rt =
    29                 new RepetitiveThread(msg, sleepTime);
    30
    31             rt.start();
    32         }
    33     }
    34 }
    
  • Java applications keep running until there are no more non-daemon threads.
  • Extending Thread often difficult because its hard to fit Thread into the inheritance hierarchy.

Implementing Runnable

  • Often more flexible to implement Runnable than extend Thread:

    1 // In file threads/ex2/Animal.java
    2 public class Animal {
    3 }
    
     1 // In file threads/ex2/Cat.java
     2 public class Cat extends Animal implements Runnable {
     3
     4     private final String msg;
     5     private final long sleepTime;
     6
     7     public Cat(String msg, long sleepTime) {
     8         this.msg = msg;
     9         this.sleepTime = sleepTime;
    10     }
    11
    12     public void run() {
    13
    14         for (;;) {
    15
    16             System.out.println(msg);
    17             try {
    18                 Thread.sleep(sleepTime);
    19             }
    20             catch (InterruptedException e) {
    21             }
    22         }
    23     }
    24 }
    
     1 // In Source Packet in file threads/ex2/Example2.java
     2 public class Example2 {
     3
     4     // Args to this application specify "msg"
     5     // and "sleepTime" for multiple threads.
     6     // For example, the command:
     7     //
     8     // $ java Example1 Meow 100 Grrr 1000
     9     //
    10     // requests two threads, one that prints
    11     // out "Meow" every 100 milliseconds and
    12     // another that prints out "Grrr" every
    13     // 1000 milliseconds.
    14     //
    15     public static void main(String[] args) {
    16
    17         // Require an even argCount
    18         int argCount = args.length;
    19         if ((argCount / 2) == 1) {
    20             --argCount;
    21         }
    22
    23         for (int i = 0; i < argCount; i += 2) {
    24
    25             String msg = args[i];
    26             long sleepTime = Long.parseLong(args[i + 1]);
    27
    28             Cat cat = new Cat(msg, sleepTime);
    29
    30             Thread catThread = new Thread(cat);
    31             catThread.start();
    32         }
    33     }
    34 }
    

Mutual Exclusion

  • Java has an object-oriented way to deal with thread synchronization.
  • Data is protected by controlling access to code. (Hence, the data must be private.)
  • Can mark blocks of code, or entire methods, as synchronized.
  • Synchronized means only one thread at a time can execute the code.

The Thread-Safe Object

  • A state machine RGBColor object (not thread-safe)

 1 // In file objectidioms/ex6/RGBColor.java
 2 // Instances of this class are NOT thread-safe.
 3
 4 public class RGBColor {
 5
 6     private int r;
 7     private int g;
 8     private int b;
 9
10     public RGBColor(int r, int g, int b) {
11
12         checkRGBVals(r, g, b);
13
14         this.r = r;
15         this.g = g;
16         this.b = b;
17     }
18
19     public void setColor(int r, int g, int b) {
20
21         checkRGBVals(r, g, b);
22
23         this.r = r;
24         this.g = g;
25         this.b = b;
26     }
27
28     /**
29     * returns color in an array of three ints: R, G, and B
30     */
31     public int[] getColor() {
32
33         int[] retVal = new int[3];
34         retVal[0] = r;
35         retVal[1] = g;
36         retVal[2] = b;
37
38         return retVal;
39     }
40
41     public void invert() {
42
43         r = 255 - r;
44         g = 255 - g;
45         b = 255 - b;
46     }
47
48     private static void checkRGBVals(int r, int g, int b) {
49
50         if (r < 0 || r > 255 || g < 0 || g > 255 ||
51             b < 0 || b > 255) {
52
53             throw new IllegalArgumentException();
54         }
55     }
56 }

Write/Write Conflicts

Thread Statement r g b Color
none object represents green 0 255 0  GREEN 
blue blue thread invokes setColor(0, 0, 255) 0 255 0  GREEN 
blue checkRGBVals(0, 0, 255); 0 255 0  GREEN 
blue this.r = 0; 0 255 0  GREEN 
blue this.g = 0; 0 255 0  GREEN 
blue blue gets preempted 0 0 0  BLACK 
red red thread invokes setColor(255, 0, 0) 0 0 0  BLACK 
red checkRGBVals(255, 0, 0); 0 0 0  BLACK 
red this.r = 255; 0 0 0  BLACK 
red this.g = 0; 255 0 0  RED 
red this.b = 0; 255 0 0  RED 
red red thread returns 255 0 0  RED 
blue later, blue thread continues 255 0 0  RED 
blue this.b = 255 255 0 0  RED 
blue blue thread returns 255 0 255  MAGENTA 
none object represents magenta 255 0 255  MAGENTA 

Read/Write Conflicts

Thread Statement r g b Color
none object represents green 0 255 0  GREEN 
blue blue thread invokes setColor(0, 0, 255) 0 255 0  GREEN 
blue checkRGBVals(0, 0, 255); 0 255 0  GREEN 
blue this.r = 0; 0 255 0  GREEN 
blue this.g = 0; 0 255 0  GREEN 
blue blue gets preempted 0 0 0  BLACK 
red red thread invokes getColor() 0 0 0  BLACK 
red int[] retVal = new int[3]; 0 0 0  BLACK 
red retVal[0] = 0; 0 0 0  BLACK 
red retVal[1] = 0; 0 0 0  BLACK 
red retVal[2] = 0; 0 0 0  BLACK 
red return retVal; 0 0 0  BLACK 
red red thread returns black 0 0 0  BLACK 
blue later, blue thread continues 0 0 0  BLACK 
blue this.b = 255 0 0 0  BLACK 
blue blue thread returns 0 0 255  BLUE 
none object represents blue 0 0 255  BLUE 

Thread-Safe RGBColor Object

 1 // In file objectidioms/ex7/RGBColor.java
 2 // Instances of this class are thread-safe.
 3
 4 public class RGBColor {
 5
 6     private int r;
 7     private int g;
 8     private int b;
 9
10     public RGBColor(int r, int g, int b) {
11
12         checkRGBVals(r, g, b);
13
14         this.r = r;
15         this.g = g;
16         this.b = b;
17     }
18
19     public void setColor(int r, int g, int b) {
20
21         checkRGBVals(r, g, b);
22
23         synchronized (this) {
24
25             this.r = r;
26             this.g = g;
27             this.b = b;
28         }
29     }
30
31     /**
32     * returns color in an array of three ints: R, G, and B
33     */
34     public int[] getColor() {
35
36         int[] retVal = new int[3];
37
38         synchronized (this) {
39
40             retVal[0] = r;
41             retVal[1] = g;
42             retVal[2] = b;
43         }
44
45         return retVal;
46     }
47
48     public synchronized void invert() {
49
50         r = 255 - r;
51         g = 255 - g;
52         b = 255 - b;
53     }
54
55     private static void checkRGBVals(int r, int g, int b) {
56
57         if (r < 0 || r > 255 || g < 0 || g > 255 ||
58             b < 0 || b > 255) {
59
60             throw new IllegalArgumentException();
61         }
62     }
63 }

Ready for Threads

Thread Statement r g b Color
none object represents green 0 255 0  GREEN 
blue blue thread invokes setColor(0, 0, 255) 0 255 0  GREEN 
blue checkRGBVals(0, 0, 255); 0 255 0  GREEN 
blue blue thread acquires lock 0 255 0  GREEN 
blue this.r = 0; 0 255 0  GREEN 
blue this.g = 0; 0 255 0  GREEN 
blue blue gets preempted 0 0 0  BLACK 
red red thread invokes setColor(255, 0, 0) 0 0 0  BLACK 
red checkRGBVals(255, 0, 0); 0 0 0  BLACK 
red red thread blocks because object locked 0 0 0  BLACK 
blue later, blue thread continues 0 0 0  BLACK 
blue this.b = 255 0 0 0  BLACK 
blue blue thread returns and releases lock 0 0 255  BLUE 
red later, red thread acquires lock and continues 0 0 255  BLUE 
red this.r = 255; 0 0 255  BLUE 
red this.g = 0; 255 0 255  MAGENTA 
red this.b = 0; 255 0 255  MAGENTA 
red red thread returns and releases lock 255 0 0  RED 
none object represents red 255 0 0  RED 

The Thread-Safe Object

  • Make instance variables private
  • Figure out what the monitor regions should be and mark them synchronized
  • Make objects thread-safe only if they'll actually be used in a multi-threaded environment
  • Why? Performance hit from acquiring the lock and the possibility of deadlock

Synchronized Class Methods

  • Can also synchronize class methods, as in:

    // In file Cat.java
    public class Cat {
        public static final int MAX_LIVES = 9;
        private static Cat[] lives = new Cat[MAX_LIVES];
        public static synchronized Cat[] getLives() {
            return lives;
        }
        //...
    }
    
  • To enter a synchronized class method, must lock the class's java.lang.Class object.

Thread Cooperation

  • Mutual exclusion is only half of the thread synchronization story: Java also supports thread cooperation.
  • Example: Producer thread and consumer thread

    Thread Action Data
    consumer Any Data? none
    consumer WAIT none
    producer Buffer Full? none
    producer Give 1, 2, 3
    producer NOTIFY 1, 2, 3
    producer Process 1, 2, 3
    consumer Any Data? 1, 2, 3
    consumer Take none
    consumer NOTIFY none
    consumer Process none
    consumer Any Data? none
    consumer WAIT none
    producer Buffer Full? none
    producer Give 5, 7, 11
    producer NOTIFY 5, 7, 11
    producer Process 5, 7, 11
    producer Buffer Full? 5, 7, 11
    producer WAIT 5, 7, 11
    consumer Any Data? 5, 7, 11
    consumer Take none
    consumer NOTIFY none
    consumer Process none
    producer Buffer Full? none
    producer Give 13, 17, 19
    producer NOTIFY 13, 17, 19
    producer Process 13, 17, 19
    consumer Any Data? 13, 17, 19
    consumer Take none
    consumer NOTIFY none
    consumer Process none
    consumer Any Data? none
    consumer WAIT none

The Java Monitor

  • A monitor is like a building that contains one special room (which usually contains some data) that can be occupied by only one thread at a time.


Cooperation Example

 1 // In file threads/ex6/IntBuffer.java
 2 public class IntBuffer {
 3
 4     private final int buffSize;
 5     private int[] buff;
 6
 7     // Keeps track of next buff array location
 8     // to be filled. When nextBuffIndex ==
 9     // buffSize, the buffer is full. When
10     // nextBuffIndex == 0, the buffer is
11     // empty.
12     private int nextBuffIndex;
13
14     IntBuffer(int buffSize) {
15
16         this.buffSize = buffSize;
17         buff = new int[buffSize];
18     }
19
20     public synchronized void add(int val) {
21
22         while (nextBuffIndex == buffSize) {
23
24             try {
25                 wait();
26             }
27             catch (InterruptedException e) {
28             }
29         }
30
31         buff[nextBuffIndex] = val;
32         ++nextBuffIndex;
33
34         notifyAll();
35     }
36
37     public synchronized int removeNext() {
38
39         while (nextBuffIndex == 0) {
40
41             try {
42                 wait();
43             }
44             catch (InterruptedException e) {
45             }
46         }
47
48         // This buffer is FIFO, so remove the
49         // first int added and shift the rest
50         // over.
51         int val = buff[0];
52
53         --nextBuffIndex;
54         for (int i = 0; i < nextBuffIndex; ++i) {
55
56             buff[i] = buff[i + 1];
57         }
58
59         notifyAll();
60         return val;
61     }
62 }

 1 // In file threads/ex6/PrimeNumberGenerator.java
 2 public class PrimeNumberGenerator implements Runnable {
 3
 4     private final IntBuffer buff;
 5
 6     public PrimeNumberGenerator(IntBuffer buff) {
 7
 8         this.buff = buff;
 9     }
10
11     public void run() {
12
13         int primeNum = 1;
14         int numToCheck = 2;
15
16         buff.add(primeNum);
17
18         for (;;) {
19
20             boolean foundPrime = true;
21
22             for (int divisor = numToCheck / 2; divisor > 1;
23                 --divisor) {
24
25                 if (numToCheck % divisor == 0) {
26                     foundPrime = false;
27                     break;
28                 }
29             }
30
31             if (foundPrime) {
32                 primeNum = numToCheck;
33                 buff.add(primeNum);
34             }
35
36             ++numToCheck;
37         }
38     }
39 }

 1 // In source packet in file threads/ex6/IntPrinter.java
 2 public class IntPrinter implements Runnable {
 3
 4     private final IntBuffer buff;
 5
 6     public IntPrinter(IntBuffer buff) {
 7
 8         this.buff = buff;
 9     }
10
11     public void run() {
12
13         for (;;) {
14
15             int val = buff.removeNext();
16             System.out.println(val);
17         }
18     }
19 }

 1 // In file threads/ex6/Example6.java
 2 public class Example6 {
 3
 4     public static void main(String[] args) {
 5
 6         IntBuffer buff = new IntBuffer(3);
 7
 8         PrimeNumberGenerator png = new PrimeNumberGenerator(buff);
 9         IntPrinter ip = new IntPrinter(buff);
10
11         Thread producer = new Thread(png);
12         Thread consumer = new Thread(ip);
13
14         producer.start();
15         consumer.start();
16     }
17 }

Thread Blocking

  • A thread can be in any of 4 states:

    • new
    • runnable
    • dead
    • blocked

  • A thread can be blocked for any of 4 reasons:

    • Sleeping (the thread invoked sleep())
    • In entry set of a monitor (the thread invoked a synchronized method)
    • In wait set of a monitor (the thread invoked wait())
    • Waiting for an I/O operation

Program Liveness

  • Liveness means a program will isn't "hung" and will eventually do something useful.
  • A multi-threaded program can lose its liveness in several ways:

    • Deadlock
    • Unsatisfied wait condition
    • Starvation

  • Thread safety often conflicts with thread liveness.

    • If no synchronized methods, program can't deadlock.

Thread Scheduling

  • The JVM holds non-blocked threads in priority-based scheduling queues.

    • By default, each new thread gets the same priority as its creator.
    • Can change a thread's priority by invoking setPriority().

  • JVMs are encouraged to:

    • Cycle through highest priority threads (not necessarily in a fair way).
    • Preempt lower priority threads in favor of higher priority threads.

  • Invoking yield() indicates to the JVM that you are ready for a rest.
  • Don't depend on "time-slicing" for program correctness.

Exercise: The Dreaded, Threaded Fibonacci Generator

Create a Java application named Problem1 that generates the Fibonacci sequence. The first two numbers of the Fibonacci sequence are 1 and 1. Each subsequent number is calculated by summing the previous two numbers, as in: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, and so on.

Input to the Application

The Problem1 application will write the Fibonacci sequence to the standard output. The Problem1 application, which requires no command line arguments, should print out the first 92 Fibonacci numbers The output will look like:

1
1
2
3
5
8
13
<...>
The maximum of 92 arises because the 93rd Fibonacci number is too big to express in a Java long. The biggest Fibonacci number that will fit in Java's long (a 64 bit signed integer) is 7540113804746346429L, which is the 92nd Fibonacci number.

Structure of the Application

The application will be made up of four classes, named:

FibonacciGenerator.java
LongBuffer.java
LongBufferToOutputThread.java
Problem1.java

The application will contain three threads, the main thread and two extra threads that the main thread will start. The two extra threads are defined by FibonacciGenerator, which implements Runnable, and LongBufferToOutputThread, which directly subclasses class Thread.

The main() method of the Problem1 application will create and start these two threads and connect the output of the FibonacciGenerator thread to the input of the LongBufferToOutputThread. The Fibonacci numbers will be generated by the FibonacciGenerator thread, which writes one long value at time into a LongBuffer. The LongBufferToOutputThread will then read long's from the LongBuffer and write them to the standard output.

Classes of the Application

Class Problem1

The main() method should:

  • Create a LongBuffer object with a buffer size of 3.
  • Create a FibonacciGenerator. object
  • Create a LongBufferToOutputThread object.
  • Start the FibonacciGenerator and LongBufferToOutputThread threads.
  • This main thread is now finished and can just return from the main() method.

Class LongBuffer

You can base this class on the IntBuffer class from the lecture slides, which is in the Threads/examples/ex6 directory of the sample code:

// In source packet in file threads/ex6/IntBuffer.java
public class IntBuffer {
    private final int buffSize;
    private int[] buff;
    // Keeps track of next buff array location
    // to be filled. When nextBuffIndex ==
    // buffSize, the buffer is full. When
    // nextBuffIndex == 0, the buffer is
    // empty.
    private int nextBuffIndex;
    IntBuffer(int buffSize) {
        this.buffSize = buffSize;
        buff = new int[buffSize];
    }
    public synchronized void add(int val) {
        while (nextBuffIndex == buffSize) {
            try {
                wait();
            }
            catch (InterruptedException e) {
            }
        }
        buff[nextBuffIndex] = val;
        ++nextBuffIndex;
        notifyAll();
    }
    public synchronized int removeNext() {
        while (nextBuffIndex == 0) {
            try {
                wait();
            }
            catch (InterruptedException e) {
            }
        }
        // This buffer is FIFO, so remove the
        // first int added and shift the rest
        // over.
        int val = buff[0];
        --nextBuffIndex;
        for (int i = 0; i < nextBuffIndex; ++i) {
            buff[i] = buff[i + 1];
        }
        notifyAll();
        return val;
    }
}

Basically, LongBuffer has to do a similar thing to what IntBuffer does, but for longs instead of ints. It needs an add() method and a long removeNext() method, and it must assume different threads will be calling these methods. Thus, the add() and removeNext() methods must be synchronized and use wait() and notifyAll().

Class FibonacciGenerator

This class extends Object and implements Runnable. It has one constructor, which takes one argument: a LongBuffer reference.

It's run() method simply produces the Fibonacci sequence one long at a time and writes each one to the LongBuffer as it is produced. To indicate that it is finished producing numbers, the FibonacciGenerator class declares a public static final int END_OF_DATA field that is initialized to -1. When the FibonacciGenerator's run() method is done generating the first 92 Fibonacci numbers, it writes an END_OF_DATA to the LongBuffer. After that, this thread is finished and the run() method simply returns.

Class LongBufferToOutputThread

This class extends Thread. It has one constructor, which takes one argument: a LongBuffer.

It's run() method simply reads one long at a time from the LongBuffer and writes it as a String to the standard output, placing a return ('\n') after each number it prints. It keeps doing this until it reads an FibonacciGenerator.END_OF_DATA from the LongBuffer. When it finds END_OF_DATA, the run() method returns, and this thread expires.

Odds and Ends

How the app knows to terminate: A Java application terminates when all non-daemon threads expire. In this application, there are three non-daemon threads. The main thread sets up and starts the other two threads, then returns. One thread down. The FibonacciGenerator thread generates the numbers, stores them into the LongBuffer, then writes an END_OF_DATA into the LongBuffer, and returns. By returning from run(), the FibonacciGenerator thread expires. Two threads down. The LongBufferToOutputThread reads from the LongBuffer and writes to the standard output until it finds an END_OF_DATA in the LongBuffer. It then returns. By returning from run(), the LongBufferToOutputThread thread expires. Because this is the third and only remaining non-daemon thread, the entire application terminates.

'java core' 카테고리의 다른 글

Annotation  (0) 2005.03.18
Java condition variable  (0) 2005.02.18
Threads from aritma  (0) 2005.02.12
Reference object model from java world  (0) 2005.01.28
Garbage collection from javaworld  (0) 2005.01.28
자바 코드 컨벤션  (0) 2005.01.24
Posted by 김용환 '김용환'

댓글을 달아 주세요