线程基础
每个用户进程有自己的地址空间。
系统为每个用户进程创建一个 task_struct来描述该进程。
该结构体中包含了一个指针指向该进程的虚拟地址空间映射表。
实际上task_struct 和地址空间映射表一起用来,表示一个进程线程基础。
由于进程的地址空间是私有的,因此在进程间上下文切换时,系统开销比较大。
为了提高系统的性能,许多操作系统规范里引入了轻量级进程的概念,也被称为线程。
在同一个进程中创建的线程共享该进程的地址空间。
Linux里同样用task_struct来描述一个线程。线程和进程都参与统一的调度
通常线程指的是共享相同地址空间的多个任务
使用多线程的好处
大大提高了任务切换的效率线程基础
多线程通过第三方的线程库来实现
New POSIX Thread Library (NPTL)是早期Linux Threads的改进
采用1:1的线程模型
显著的提高了运行效率
NPTL线程库中提供了如下基本操作
删除线程
创建线程
控制线程
线程间同步和互斥机制
信号量
互斥锁
条件变量
Linux线程编程线程基本编程 (1)
创建线程实际上就是确定调用该线程函数的入口点,这里通常使用的函数是pthread_create()。在线程创建以后,就开始运行相关的线程函数,在该函数运行完之后,该线程也就退出了,这也是线程退出一种方法。另一种退出线程的方法是使用函数pthread_exit(),这是线程的主动行为。
由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放。正如进程之间可以用wait()系统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。pthread_join()可以用于将当前线程挂起来等待线程的结束。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。
线程示例1:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> char message[32] = “Hello World”; void *thread_function(void *arg); int main(int argc, char *argv[]) { pthread_t a_thread; void *thread_result; if (pthread_create(&a_thread, NULL, thread_function, (void *)message) < 0) /*使用缺省属性创建线程*/{ perror(“fail to pthread_create”); exit(-1); } printf(“waiting for thread to finish\n”); if (pthread_join(a_thread, &thread_result) < 0) // 等待线程结束 { perror(“fail to pthread_join”); exit(-1); } printf(“MESSAGE is now %s\n”, message); return 0; }void *thread_function(void *arg) { printf(“thread_function is running, argument is %s\n”, (char *)arg); strcpy(message, “marked by thread”); pthread_exit(“Thank you for the cpu time”); }
线程实例2
#include<pthread.h> #include<stdio.h> #include<stdlib.h> int a = 0; pthread_mutex_t mutex; void * hello() { while(1) { pthread_mutex_lock(&mutex); printf("a = %d\n",a); printf("son sleep(1)\n"); sleep(1); pthread_mutex_unlock(&mutex); sleep(1); } pthread_exit("see you"); } int main() { pthread_t id; pthread_create(&id,NULL,hello,NULL);//新建一个线程 pthread_mutex_init(&mutex,NULL);//初始化一个互斥锁 while(1) { pthread_mutex_lock(&mutex);//判断有没有上锁,有的话,就等待,没有的话就上锁 a++; printf("father sleep(1)\n"); sleep(1); pthread_mutex_unlock(&mutex);//解锁 sleep(1); } pthread_cancel(id);//发出线程结束命令给线程id pthread_mutex_destroy(&mutex);//销毁互斥锁 }
-lpthread : 链接pthread库互斥锁线程控制,编译的时候一定要加上,否则会出现以下错误
pthread.c:(.text+0x89):对‘pthread_create’未定义的引用
pthread.c:(.text+0xa1):对‘pthread_cancel’未定义的引用
pthread.c:(.text+0xb5):对‘pthread_join’未定义的引用
• 互斥锁初始化:pthread_mutex_init()
• 互斥锁上锁:pthread_mutex_lock()
• 互斥锁判断上锁:pthread_mutex_trylock()
• 互斥锁接锁:pthread_mutex_unlock()
• 消除互斥锁:pthread_mutex_destroy()所需头文件 #include < pthread.h >
函数原型 ,
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr )// 初始化互斥锁
函数参数
mutex:互斥锁属性 // NULL
attr:NULL表示缺省属性
函数返回值
成功:0
出错:-1
函数原型 int pthread_mutex_lock(pthread_mutex_t *mutex)// 申请互斥锁
函数参数 mutex:互斥锁
函数返回值
成功:0
出错:-1
int pthread_mutex_trylock(pthread_mutex_t *mutex);所需头文件 #include <pthread.h>
函数原型
int pthread_mutex_unlock(pthread_mutex_t *mutex) // 释放互斥锁
函数参数 mutex
mutex:互斥锁
函数返回值 0
成功:0
出错:-1线程互斥示例
#include<pthread.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h> struct mess//使用结构体可以一次性传递多个参数 { int a; char b; }; void * hello(void *p) { struct mess *m; m = (struct mess*)p;//该函数需要传递多个参数就使用结构体,将所有的参数都放入其中。 printf("I am xiancheng!!\n");//线程运行完后自动销毁 printf("arg1 is %d\n",(*m).a); printf("arg2 is %c\n",(*m).b); pthread_exit("hello() is over...");//函数的返回 } int main() { pthread_t threadid; struct mess m; m.a = 10; m.b = 'b'; pthread_create(&threadid,NULL,hello,(void *)&m);//创建一个线程 sleep(1);//防止子线程还没结束,main线程就已经结束了 pthread_cancel(threadid);//非阻塞函数 pthread_join(threadid,NULL); return 0; }
详细内容,可下载pdf文件:多线程编程.pdf