diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs
index dbcf37cc..7c8ef58a 100644
--- a/os/src/syscall/mod.rs
+++ b/os/src/syscall/mod.rs
@@ -45,7 +45,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
         SYSCALL_FORK => sys_fork(),
         SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize),
         SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32),
-        SYSCALL_THREAD_CREATE => sys_thread_create(args[0]),
+        SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]),
         SYSCALL_GETTID => sys_gettid(),
         SYSCALL_WAITTID => sys_waittid(args[0]) as isize,
         SYSCALL_MUTEX_CREATE => sys_mutex_create(args[0] == 1),
diff --git a/os/src/syscall/thread.rs b/os/src/syscall/thread.rs
index d9e42ba1..fa3b181a 100644
--- a/os/src/syscall/thread.rs
+++ b/os/src/syscall/thread.rs
@@ -1,7 +1,7 @@
 use alloc::sync::Arc;
 use crate::{mm::kernel_token, task::{TaskControlBlock, add_task, current_task}, trap::{TrapContext, trap_handler}};
 
-pub fn sys_thread_create(entry: usize) -> isize {
+pub fn sys_thread_create(entry: usize, arg: usize) -> isize {
     let task = current_task().unwrap();
     let process = task.process.upgrade().unwrap();
     // create a new thread
@@ -30,6 +30,7 @@ pub fn sys_thread_create(entry: usize) -> isize {
         new_task.kstack.get_top(),
         trap_handler as usize,
     );
+    (*new_task_trap_cx).x[10] = arg;
     new_task_tid as isize
 }
 
diff --git a/user/src/bin/race_adder.rs b/user/src/bin/race_adder.rs
index 0392b346..bae009ec 100644
--- a/user/src/bin/race_adder.rs
+++ b/user/src/bin/race_adder.rs
@@ -28,7 +28,7 @@ pub fn main() -> i32 {
     let start = get_time();
     let mut v = Vec::new();    
     for _ in 0..THREAD_COUNT {
-        v.push(thread_create(f as usize) as usize);
+        v.push(thread_create(f as usize, 0) as usize);
     }
     let mut time_cost = Vec::new();
     for tid in v.iter() {
diff --git a/user/src/bin/race_adder_atomic.rs b/user/src/bin/race_adder_atomic.rs
index bb2d20e1..dfbe490e 100644
--- a/user/src/bin/race_adder_atomic.rs
+++ b/user/src/bin/race_adder_atomic.rs
@@ -11,8 +11,8 @@ use core::sync::atomic::{AtomicBool, Ordering};
 
 static mut A: usize = 0;
 static OCCUPIED: AtomicBool = AtomicBool::new(false);
-const PER_THREAD: usize = 100000;
-const THREAD_COUNT: usize = 8;
+const PER_THREAD: usize = 1000;
+const THREAD_COUNT: usize = 16;
 
 unsafe fn f() -> ! {
     let mut t = 2usize;
@@ -34,7 +34,7 @@ pub fn main() -> i32 {
     let start = get_time();
     let mut v = Vec::new();    
     for _ in 0..THREAD_COUNT {
-        v.push(thread_create(f as usize) as usize);
+        v.push(thread_create(f as usize, 0) as usize);
     }
     let mut time_cost = Vec::new();
     for tid in v.iter() {
diff --git a/user/src/bin/race_adder_loop.rs b/user/src/bin/race_adder_loop.rs
index 64e431a4..035772e2 100644
--- a/user/src/bin/race_adder_loop.rs
+++ b/user/src/bin/race_adder_loop.rs
@@ -10,8 +10,8 @@ use alloc::vec::Vec;
 
 static mut A: usize = 0;
 static mut OCCUPIED: bool = false;
-const PER_THREAD: usize = 10000;
-const THREAD_COUNT: usize = 8;
+const PER_THREAD: usize = 1000;
+const THREAD_COUNT: usize = 16;
 
 unsafe fn f() -> ! {
     let mut t = 2usize;
@@ -35,7 +35,7 @@ pub fn main() -> i32 {
     let start = get_time();
     let mut v = Vec::new();    
     for _ in 0..THREAD_COUNT {
-        v.push(thread_create(f as usize) as usize);
+        v.push(thread_create(f as usize, 0) as usize);
     }
     let mut time_cost = Vec::new();
     for tid in v.iter() {
diff --git a/user/src/bin/race_adder_mutex_blocking.rs b/user/src/bin/race_adder_mutex_blocking.rs
index 3df340f7..0424eba4 100644
--- a/user/src/bin/race_adder_mutex_blocking.rs
+++ b/user/src/bin/race_adder_mutex_blocking.rs
@@ -10,8 +10,8 @@ use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
 use alloc::vec::Vec;
 
 static mut A: usize = 0;
-const PER_THREAD: usize = 10000;
-const THREAD_COUNT: usize = 8;
+const PER_THREAD: usize = 1000;
+const THREAD_COUNT: usize = 16;
 
 unsafe fn f() -> ! {
     let mut t = 2usize;
@@ -32,7 +32,7 @@ pub fn main() -> i32 {
     assert_eq!(mutex_blocking_create(), 0);
     let mut v = Vec::new();    
     for _ in 0..THREAD_COUNT {
-        v.push(thread_create(f as usize) as usize);
+        v.push(thread_create(f as usize, 0) as usize);
     }
     let mut time_cost = Vec::new();
     for tid in v.iter() {
diff --git a/user/src/bin/race_adder_mutex_spin.rs b/user/src/bin/race_adder_mutex_spin.rs
index 038e01aa..fb168666 100644
--- a/user/src/bin/race_adder_mutex_spin.rs
+++ b/user/src/bin/race_adder_mutex_spin.rs
@@ -32,7 +32,7 @@ pub fn main() -> i32 {
     assert_eq!(mutex_create(), 0);
     let mut v = Vec::new();    
     for _ in 0..THREAD_COUNT {
-        v.push(thread_create(f as usize) as usize);
+        v.push(thread_create(f as usize, 0) as usize);
     }
     let mut time_cost = Vec::new();
     for tid in v.iter() {
diff --git a/user/src/bin/threads.rs b/user/src/bin/threads.rs
index 7641dde5..97ce43f0 100644
--- a/user/src/bin/threads.rs
+++ b/user/src/bin/threads.rs
@@ -26,9 +26,9 @@ pub fn thread_c() -> ! {
 #[no_mangle]
 pub fn main() -> i32 {
     let mut v = Vec::new();
-    v.push(thread_create(thread_a as usize));
-    v.push(thread_create(thread_b as usize));
-    v.push(thread_create(thread_c as usize));
+    v.push(thread_create(thread_a as usize, 0));
+    v.push(thread_create(thread_b as usize, 0));
+    v.push(thread_create(thread_c as usize, 0));
     for tid in v.iter() {
         let exit_code = waittid(*tid as usize);
         println!("thread#{} exited with code {}", tid, exit_code);
diff --git a/user/src/bin/threads_arg.rs b/user/src/bin/threads_arg.rs
new file mode 100644
index 00000000..a29b23dd
--- /dev/null
+++ b/user/src/bin/threads_arg.rs
@@ -0,0 +1,39 @@
+#![no_std]
+#![no_main]
+
+#[macro_use]
+extern crate user_lib;
+extern crate alloc;
+
+use user_lib::{thread_create, waittid, exit};
+use alloc::vec::Vec;
+
+struct Argument {
+    pub ch: char,
+    pub rc: i32,
+}
+
+fn thread_print(arg: *const Argument) -> ! {
+    let arg = unsafe { &*arg };
+    for _ in 0..1000 { print!("{}", arg.ch); }
+    exit(arg.rc)
+}
+
+#[no_mangle]
+pub fn main() -> i32 {
+    let mut v = Vec::new();
+    let args = [
+        Argument { ch: 'a', rc: 1, },
+        Argument { ch: 'b', rc: 2, },
+        Argument { ch: 'c', rc: 3, },
+    ]; 
+    for i in 0..3 {
+        v.push(thread_create(thread_print as usize, &args[i] as *const _ as usize));
+    }
+    for tid in v.iter() {
+        let exit_code = waittid(*tid as usize);
+        println!("thread#{} exited with code {}", tid, exit_code);
+    }
+    println!("main thread exited.");
+    0
+}
diff --git a/user/src/lib.rs b/user/src/lib.rs
index 356360e9..6f034d6e 100644
--- a/user/src/lib.rs
+++ b/user/src/lib.rs
@@ -104,7 +104,7 @@ pub fn sleep(sleep_ms: usize) {
     sys_sleep(sleep_ms);
 }
 
-pub fn thread_create(entry: usize) -> isize { sys_thread_create(entry) }
+pub fn thread_create(entry: usize, arg: usize) -> isize { sys_thread_create(entry, arg) }
 pub fn gettid() -> isize { sys_gettid() }
 pub fn waittid(tid: usize) -> isize {
     loop {
diff --git a/user/src/syscall.rs b/user/src/syscall.rs
index 793b36dd..0edcb9ce 100644
--- a/user/src/syscall.rs
+++ b/user/src/syscall.rs
@@ -90,8 +90,8 @@ pub fn sys_waitpid(pid: isize, exit_code: *mut i32) -> isize {
     syscall(SYSCALL_WAITPID, [pid as usize, exit_code as usize, 0])
 }
 
-pub fn sys_thread_create(entry: usize) -> isize {
-    syscall(SYSCALL_THREAD_CREATE, [entry, 0, 0])
+pub fn sys_thread_create(entry: usize, arg: usize) -> isize {
+    syscall(SYSCALL_THREAD_CREATE, [entry, arg, 0])
 }
 
 pub fn sys_gettid() -> isize {