Chun Lin
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # What's ```pthread_mutex_t``` ? ```pthread_mutex_t``` is a arbitrary structure in c that represent locks that can perform lock and unlock for threads `pthread_mutex_t` is a structure defined in the **POSIX Threads (Pthreads)** library, and it represents a **mutex (mutual exclusion)** object. This mutex allows threads to **lock** and **unlock** access to shared resources, ensuring that only one thread can operate on the resource at any given time. It's a fundamental tool for synchronizing threads and preventing race conditions in multithreaded programs. --- ### **Key Features of `pthread_mutex_t`:** 1. **Represents a Lock:** - The `pthread_mutex_t` object acts as a lock that threads can acquire or release. - When a thread locks the mutex, other threads attempting to lock it will block (wait) until the mutex is unlocked. 2. **Predefined in C:** - It is not an arbitrary structure but part of the POSIX standard. - The exact implementation details are abstracted from the programmer and handled by the system. 3. **Thread-Safe Operations:** - It provides mechanisms to ensure only one thread accesses a critical section at a time. --- ### **Basic Operations:** The mutex provides these key operations: 1. **Initialize the Mutex:** - Use `pthread_mutex_init` to set up a mutex. ```c pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); ``` - You can also use `PTHREAD_MUTEX_INITIALIZER` for static initialization: ```c pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ``` 2. **Lock the Mutex:** - A thread locks the mutex before entering a critical section: ```c pthread_mutex_lock(&mutex); ``` - If another thread has already locked the mutex, this call blocks until the mutex becomes available. 3. **Unlock the Mutex:** - After completing its operation on the shared resource, the thread unlocks the mutex: ```c pthread_mutex_unlock(&mutex); ``` 4. **Destroy the Mutex:** - When the mutex is no longer needed, free its resources: ```c pthread_mutex_destroy(&mutex); ``` --- ### **Example: Protecting a Shared Resource** Here’s a simple example using `pthread_mutex_t` to protect a shared counter: ```c #include <pthread.h> #include <stdio.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // Static mutex initialization int counter = 0; void *increment_counter(void *arg) { for (int i = 0; i < 1000; i++) { pthread_mutex_lock(&mutex); // Lock the mutex counter++; // Critical section pthread_mutex_unlock(&mutex); // Unlock the mutex } return NULL; } int main() { pthread_t t1, t2; pthread_create(&t1, NULL, increment_counter, NULL); pthread_create(&t2, NULL, increment_counter, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); printf("Final counter value: %d\n", counter); pthread_mutex_destroy(&mutex); // Clean up the mutex return 0; } ``` --- ### **How Does It Work?** - `pthread_mutex_t` ensures that only one thread at a time can increment the shared `counter`. - Without the mutex, both threads could read and write `counter` simultaneously, leading to incorrect results (a race condition). --- ### **Summary** `pthread_mutex_t` is a predefined structure in C that acts as a synchronization primitive for managing **locks** in multithreaded environments. It is essential for ensuring thread safety when accessing shared resources. --- # Important pthread_ related Functions ## `pthread_create` `pthread_create` is a function used to create a new thread in a program that uses POSIX threads (pthreads). A thread is a lightweight process that can run concurrently with other threads in the same program. The `pthread_create` function is used to spawn a new thread and define what that thread will do when it starts. #### Function Signature ```c int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); ``` #### Parameters: 1. **`pthread_t *thread`**: - This is the pointer to a `pthread_t` variable that will hold the ID of the newly created thread. - The thread ID is unique and is used to identify the thread for future operations, such as joining or canceling. 2. **`const pthread_attr_t *attr`**: - This is a pointer to a `pthread_attr_t` structure that defines various thread attributes (like stack size or scheduling policy). - If this is `NULL`, the default thread attributes are used (standard settings). 3. **`void *(*start_routine) (void *)`**: - This is a pointer to the function that the new thread will execute when it starts. The function must take a `void *` argument (this is often used to pass a pointer to data) and return a `void *`. - The function signature for the start routine must be `void *start_routine(void *arg)`. 4. **`void *arg`**: - This is a pointer to the data that you want to pass to the thread's start routine. The argument can be any data type cast to `void *`, but you often pass a pointer to some struct or variable that the thread needs. #### Return Value: - **`0`**: The function succeeds in creating a thread. - **Non-zero value**: An error code if the thread could not be created. #### Example: Here’s a simple example where we create a thread that prints a message. The thread executes a function called `print_message` when it starts. ```c #include <stdio.h> #include <pthread.h> #include <stdlib.h> void *print_message(void *arg) { printf("Hello from the new thread! Argument: %s\n", (char *)arg); return NULL; } int main() { pthread_t thread; // Declare a thread variable char *message = "This is a thread argument!"; // Argument to pass to the thread // Create a new thread that executes the print_message function if (pthread_create(&thread, NULL, print_message, (void *)message)) { printf("Error creating thread\n"); return 1; } // Wait for the thread to finish before continuing if (pthread_join(thread, NULL)) { printf("Error joining thread\n"); return 1; } printf("Main thread finished\n"); return 0; } ``` ### Explanation of the Example: - **`pthread_create(&thread, NULL, print_message, (void *)message)`**: - This creates a new thread and passes the string `message` as an argument to the `print_message` function. - The new thread will execute `print_message` with `message` as the argument, which will print `"Hello from the new thread! Argument: This is a thread argument!"`. - **`pthread_join(thread, NULL)`**: - This is used to wait for the new thread to finish before proceeding. The main thread blocks until the `thread` finishes executing. - If the thread had not finished when the `pthread_join` is called, the main thread would wait for it to complete. - **Output**: ``` Hello from the new thread! Argument: This is a thread argument! Main thread finished ``` ### Key Points: - Threads are executed concurrently, meaning that the main thread can continue its execution while the new thread runs in parallel. - The start routine (in this case, `print_message`) is where the thread performs its task. You can pass any data to the thread's routine by using the `arg` parameter. - `pthread_create` doesn't block the main thread. To ensure the main thread waits for the new thread to finish, we use `pthread_join`. ### Summary: `pthread_create` is essential for creating new threads in a multi-threaded program. It allows different parts of your program to run concurrently, improving efficiency. After creating a thread, you can use `pthread_join` to synchronize with it and wait for its completion. --- ## `pthread_join()` `pthread_join` is a function that allows a thread to wait for another thread to finish its execution. It is used to synchronize threads by blocking the calling thread until the specified thread has finished executing. It ensures that the resources used by the thread (like memory) are cleaned up only after the thread has finished. #### Function Signature: ```c int pthread_join(pthread_t thread, void **retval); ``` #### Parameters: 1. **`pthread_t thread`**: - The ID of the thread that the calling thread wants to wait for. It is a `pthread_t` type variable that identifies a specific thread created using `pthread_create`. 2. **`void **retval`**: - A pointer to a pointer where the exit status of the thread will be stored. This is where the return value of the thread's start routine will be saved. - If you don't need the return value, you can pass `NULL`. #### Return Value: - **`0`**: The function succeeds and the calling thread successfully joins with the specified thread. - **Non-zero value**: An error occurred (e.g., if the specified thread does not exist or the calling thread has already joined with it). #### Key Points: - `pthread_join` is necessary to ensure proper cleanup of resources used by a thread. - Without `pthread_join`, the main thread may terminate while other threads are still running, causing undefined behavior and resource leakage. - It is used when you need to wait for a thread to complete before proceeding further in the program. ### Example 1: Basic Usage of `pthread_join` Here’s a simple example where a thread is created to print a message, and the main thread waits for the new thread to finish using `pthread_join`. ```c #include <stdio.h> #include <pthread.h> #include <stdlib.h> void *print_message(void *arg) { printf("Hello from the new thread!\n"); return NULL; } int main() { pthread_t thread; // Declare a thread variable // Create a new thread that executes the print_message function if (pthread_create(&thread, NULL, print_message, NULL)) { printf("Error creating thread\n"); return 1; } // Wait for the thread to finish before continuing if (pthread_join(thread, NULL)) { printf("Error joining thread\n"); return 1; } printf("Main thread finished\n"); return 0; } ``` #### Explanation: - The main thread creates a new thread using `pthread_create`. - The main thread then calls `pthread_join(thread, NULL)` to wait for the new thread (`thread`) to finish before proceeding with the rest of the program. - The output will be: ``` Hello from the new thread! Main thread finished ``` ### Example 2: `pthread_join` with Return Values In this example, the thread returns a value, and the main thread retrieves it using `pthread_join`. ```c #include <stdio.h> #include <pthread.h> #include <stdlib.h> void *calculate_square(void *arg) { int *num = (int *)arg; int *result = malloc(sizeof(int)); // Allocate memory for the result *result = (*num) * (*num); return result; } int main() { pthread_t thread; // Declare a thread variable int num = 5; int *square; // Create a new thread that calculates the square of 'num' if (pthread_create(&thread, NULL, calculate_square, &num)) { printf("Error creating thread\n"); return 1; } // Wait for the thread to finish and get the return value if (pthread_join(thread, (void **)&square)) { printf("Error joining thread\n"); return 1; } printf("The square of %d is %d\n", num, *square); free(square); // Don't forget to free the allocated memory return 0; } ``` #### Explanation: - The thread calculates the square of a number and returns the result. - The `pthread_join` function is used to obtain the return value (`square`) from the thread. The return value is a pointer to an integer, which is cast to `void **` for passing to `pthread_join`. - The output will be: ``` The square of 5 is 25 ``` #### Key Notes: - **Return values in threads**: The `return` statement in a thread's start routine can be used to send back a result. The main thread retrieves this result by calling `pthread_join` and providing a location to store the return value. - **Memory management**: If the thread dynamically allocates memory (as in the second example), the main thread is responsible for freeing it after it is done using the returned value to avoid memory leaks. ### Example 3: Using `pthread_join` in a Loop (Multiple Threads) Here’s an example of creating multiple threads and using `pthread_join` to wait for all of them to finish. ```c #include <stdio.h> #include <pthread.h> #include <stdlib.h> void *print_thread_id(void *arg) { printf("Thread ID: %ld\n", pthread_self()); return NULL; } int main() { pthread_t threads[3]; // Declare an array of threads int i; // Create 3 threads for (i = 0; i < 3; i++) { if (pthread_create(&threads[i], NULL, print_thread_id, NULL)) { printf("Error creating thread %d\n", i); return 1; } } // Wait for all threads to finish for (i = 0; i < 3; i++) { if (pthread_join(threads[i], NULL)) { printf("Error joining thread %d\n", i); return 1; } } printf("All threads finished\n"); return 0; } ``` #### Explanation: - We create 3 threads, each of which prints its thread ID using `pthread_self()`. - After creating all the threads, the main thread uses `pthread_join` in a loop to wait for each thread to finish before proceeding. - The output will be: ``` Thread ID: 139747349055744 Thread ID: 139747340663040 Thread ID: 139747332270336 All threads finished ``` ### Summary: - `pthread_join` is used to wait for a thread to finish. It ensures that the calling thread (usually the main thread) waits for the specified thread to complete before continuing. - It is useful for synchronization and cleaning up resources used by the thread. - You can also use `pthread_join` to retrieve the return value of the thread by passing a pointer to where the result should be stored. - Always remember to manage memory properly if the thread allocates resources that the main thread needs to free later. --- ## Usage Example Here is a simple program that demonstrates how to use `pthread_create()` and `pthread_join()` in C. In this example, we create multiple threads that print their thread IDs, and the main thread waits for each of them to finish using `pthread_join()`. ### Simple Program Example ```c #include <stdio.h> #include <pthread.h> #include <stdlib.h> // Function to be executed by each thread //pthread_self() : returns the unique identifier (ID) of the calling thread. //pthread_t thread_id = pthread_self(); void *print_thread_id(void *arg) { pthread_t thread_id = pthread_self(); printf("Thread ID: %ld\n", thread_id); // Print the thread ID return NULL; } int main() { pthread_t threads[3]; // Array to hold thread IDs int i; // Create 3 threads for (i = 0; i < 3; i++) { if (pthread_create(&threads[i], NULL, print_thread_id, NULL)) { printf("Error creating thread %d\n", i); return 1; } } // Wait for all threads to finish for (i = 0; i < 3; i++) { if (pthread_join(threads[i], NULL)) { printf("Error joining thread %d\n", i); return 1; } } printf("All threads finished\n"); return 0; } ``` ### Explanation: 1. **`print_thread_id` Function**: - Each thread executes this function. It retrieves its thread ID using `pthread_self()` and prints it. 2. **Creating Threads**: - In the `main` function, we create 3 threads using a loop. For each iteration, `pthread_create` is called to create a new thread that will run the `print_thread_id` function. 3. **Joining Threads**: - After creating the threads, the main thread waits for each thread to finish using `pthread_join`. This ensures that the main thread does not exit until all created threads have completed their execution. 4. **Output**: - Each thread prints its unique thread ID. - After all threads have finished, the main thread prints "All threads finished". ### Example Output: ``` Thread ID: 139937358019328 Thread ID: 139937349626624 Thread ID: 139937341233920 All threads finished ``` In this output, the thread IDs may differ each time you run the program. The key point is that `pthread_create` launches the threads, and `pthread_join` makes sure the main thread waits for all of them to finish before printing "All threads finished". --- ## Usage for pthread_create/join/detatch ### Usage Logic Brief For everytime a thread is created with ```pthread_create```, it should always be handled when the thread is terminated; If not using ```pthread_join```, should still use ```pthread_detach```to handle the terminated threads. The logic is like malloc/calloc and free. Yes, you are correct in understanding that every time you create a thread using `pthread_create()`, you need to properly handle its termination, just as you would manage memory allocation and deallocation with `malloc/calloc` and `free`. --- ### Threads and Resource Management - When a thread is created, it consumes system resources, including memory for its stack, and has an associated process ID (PID). Just like memory allocated with `malloc` or `calloc`, these resources need to be cleaned up when the thread finishes. If you don't properly handle its termination, you risk resource leaks or "zombie" threads, just like you'd risk memory leaks if you don’t `free` allocated memory. --- ### `pthread_join()` - **Purpose**: Waits for the thread to finish and ensures that resources associated with the thread are cleaned up once it's done. - **Use Case**: When you need to **wait** for the thread to finish, and potentially collect any return values or do some cleanup after it finishes. - **Similar to `free`**: Just as you call `free` to deallocate memory, you call `pthread_join()` to properly deallocate thread resources (i.e., the thread terminates, and its resources are freed). --- ### `pthread_detach()` - **Purpose**: Detaches the thread so that it will clean up its own resources once it finishes. No need to call `pthread_join()` after detaching. - **Use Case**: When you **don’t need to wait** for the thread to finish or collect its result but still want the system to clean up after it once it terminates. - **Similar to garbage collection**: You don’t need to manually clean up the thread; it happens automatically when the thread finishes, similar to how garbage collection might automatically clean up unused memory in some languages. However, it’s not the same as `free` because `pthread_detach()` doesn't let you directly control when the resources are cleaned up. --- ### The Analogy with `malloc/calloc` and `free` The logic of handling threads is indeed similar to managing dynamically allocated memory. Consider these parallels: - **`malloc/calloc`** → **`pthread_create()`**: - Just like memory is allocated using `malloc` or `calloc`, a thread is created with `pthread_create`. - **`free`** → **`pthread_join()`**: - Just as you need to call `free` to deallocate memory, you need to call `pthread_join()` to clean up the resources associated with a thread. - **`free` vs. `pthread_detach()`**: - Unlike `free`, which deallocates memory, `pthread_detach()` allows the system to automatically clean up the thread's resources when it finishes. You don't need to manually call `pthread_detach()`, but it's essential if you don’t want to leave zombie threads. --- ### Example: Thread Handling with `pthread_create()`, `pthread_join()`, and `pthread_detach()` #### Example with `pthread_join()`: ```c #include <stdio.h> #include <pthread.h> void* thread_function(void *arg) { printf("Thread is running...\n"); return NULL; } int main() { pthread_t thread; // Create a thread pthread_create(&thread, NULL, thread_function, NULL); // Wait for the thread to finish and clean up resources pthread_join(thread, NULL); // Like calling free() for memory printf("Thread has finished\n"); return 0; } ``` #### Example with `pthread_detach()`: ```c #include <stdio.h> #include <pthread.h> void* thread_function(void *arg) { printf("Thread is running...\n"); return NULL; } int main() { pthread_t thread; // Create a thread pthread_create(&thread, NULL, thread_function, NULL); // Detach the thread so it cleans up automatically when finished pthread_detach(thread); // Thread is cleaned up automatically when it finishes // Main can continue without waiting for the thread printf("Main thread continues...\n"); return 0; } ``` --- ### Key Points: - **When to use `pthread_join()`**: - If you need to wait for the thread to finish, use `pthread_join()` to ensure resources are cleaned up. - **When to use `pthread_detach()`**: - If you don’t need to wait for the thread or collect its return value, use `pthread_detach()`, so the thread cleans up automatically when it terminates. - **What happens without `pthread_join()` or `pthread_detach()`**: - If you don’t handle thread termination using either `pthread_join()` or `pthread_detach()`, you may end up with **zombie threads**, where the thread finishes but its resources are not cleaned up, which can lead to memory leaks. So, just as memory allocated with `malloc/calloc` must be freed to avoid memory leaks, threads created with `pthread_create()` need to be properly cleaned up, either by using `pthread_join()` (if you wait for the thread) or `pthread_detach()` (if you don’t). --- # Bash Commands to Check Thread Usage To check if threads are properly handled in a program, you can use the following Bash commands and tools: ### 1. **`htop` or `top`** - **Purpose**: Monitor running processes and threads in real time. - **Usage**: ```bash htop ``` or ```bash top -H -p <PID> ``` - **Explanation**: - In `htop`, press `F2` (Setup) and enable "Display threads in a process." - In `top`, the `-H` flag shows threads, and `-p` focuses on a specific process ID. - **What to Check**: - Look for the number of threads (`TID`) created by your program. - Ensure there aren’t excessive threads lingering after they should have terminated. --- ### 2. **`ps`** - **Purpose**: Display thread information for a specific process. - **Usage**: ```bash ps -eLf | grep <program_name> ``` - **Explanation**: - `-eL`: Show all processes with their threads (lightweight processes). - `f`: Full-format listing. - `grep`: Filter output for your program. - **What to Check**: - Count the number of threads (`LWP`) associated with your program. - Ensure terminated threads are no longer listed. --- ### 3. **`pmap`** - **Purpose**: Check memory usage, which can indicate thread leaks. - **Usage**: ```bash pmap <PID> ``` - **Explanation**: - `pmap` shows memory maps for a given process ID. - Look for excessive memory usage, which may indicate resource leaks due to unhandled threads. --- ### 4. **`valgrind` (Optional for Debugging)** - **Purpose**: Detect memory and thread leaks during program execution. - **Usage**: ```bash valgrind --tool=helgrind ./your_program ``` - **Explanation**: - `helgrind` is a thread debugger that detects thread-related errors, including resource leaks. - Look for reports of unhandled threads or memory leaks. --- ### 5. **`strace`** - **Purpose**: Trace system calls, including thread creation and termination. - **Usage**: ```bash strace -f ./your_program ``` - **Explanation**: - `-f` tracks child threads created by your program. - Look for system calls like `clone()` (used for thread creation) and ensure there’s a corresponding cleanup. --- ### Key Indicators of Proper Thread Handling: - The number of threads remains stable over time. - No excessive or lingering threads after the program finishes execution. - Memory usage doesn’t grow uncontrollably. - Tools like `valgrind` or `helgrind` report no thread or memory leaks. By combining these tools, you can confidently check whether threads are properly managed in your program.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully