进程与线程(二)
2016-04-09 15:34
357 查看
Linux中的线程机制十分特殊,从内核的角度来说并没有线程的概念,故没有为线程单独定义数据结构,通过clone()创建的Linux线程,仅被看做一个与其他进程共享某些资源的特殊进程而已;
Linxu中把线程分为内核线程,内核支持的用户线程和线程库支持的用户线程等3种类型;
1、内核线程:内核线程的创建于撤销有内核内部的需求决定,内核线程没有用户地址空间,它共享内核的正文段和内核全局数据,具有自己的内核栈,内核线程的调度由于不需要经过CPU状态的转换,所以内核线程间的上下文切换比在用户线程间快得多;
2、内核支持的用户线程:有clone()函数创建的线程;
3、线程库支持的用户线程:用户线程是通过线程库实现的,内核不参与调度,它可以在没有内核参与下创建,释放和管理,线程库提供同步和调度的方法。内核通过调度进程,进程通过线程库调度线程;
一、内核支持的用户线程
通过clone()函数进行创建;
![](https://img-blog.csdn.net/20160409143733845)
二、线程库支持的用户线程
1、POSIX线程
POSIX线程包提供一组函数,用来创建,删除和同步同一进程内的线程,使用时需要加入头文件pthread.h, 编译时需要使用-pthread来链接线程库
2、线程的创建
pthread_create与clone的区别在于:clone()创建的是一个内核支持的用户线程,对内核是可见的且由内核调度,而pthread_create创建一个线程库支持的用户线程,对内核不可见,由线程库调度;
线程的标识符:与进程类似,线程也有线程标识符,可通过pthread_self()获取;
![](https://img-blog.csdn.net/20160409153343476)
3、线程等待
4、线程同步
(1)信号量
可以参考 信号量-百度百科
(2)互斥量
通过使用互斥量,使用两个线程同时读取两个文件并统计单词个数:
5、线程终止
线程的正常退出包括以下几种
线程只是从启动例程返回,返回值是线程中的退出码;
线程被另一个线程终止;
线程自己调用pthread_exit()终止;
Linxu中把线程分为内核线程,内核支持的用户线程和线程库支持的用户线程等3种类型;
1、内核线程:内核线程的创建于撤销有内核内部的需求决定,内核线程没有用户地址空间,它共享内核的正文段和内核全局数据,具有自己的内核栈,内核线程的调度由于不需要经过CPU状态的转换,所以内核线程间的上下文切换比在用户线程间快得多;
2、内核支持的用户线程:有clone()函数创建的线程;
3、线程库支持的用户线程:用户线程是通过线程库实现的,内核不参与调度,它可以在没有内核参与下创建,释放和管理,线程库提供同步和调度的方法。内核通过调度进程,进程通过线程库调度线程;
一、内核支持的用户线程
通过clone()函数进行创建;
/*int clone(int (*fn)(void *arg),void *stack,int flags,void *arg) fn:函数指针,线程标识符 flags: CLONE_VM:父进程,子进程共享进程空间; CLONE_FS:父进程,子进程共享文件系统信息; CLONE_FILES:父进程,子进程共享打开的文件; CLONE_SIGGHLD:子进程终结或者暂停时给父进程发信号; CLONE_SIGHAND:父子进程共享信号处理函数; CLONE_PID:父子进程共享进程标识符; CLONE_VFORK:父进程在子进程释放空间时被唤醒; stack:线程所使用的内核栈; arg:传给fn的void*类型的参数 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <pthread.h> #define STACK_SIZE 1024*1024*8 void *func(void * arg) { printf("arg = %d\n",*(int *)arg); printf("PID = %d\n",getpid()); sleep(50); return (void *)0; } int main() { int clone_flag,arg; char *stack; int retval; arg = 1; clone_flag = CLONE_VM|CLONE_SIGHAND|CLONE_FS|CLONE_FILES; printf("pid = %d\n",getpid()); stack = (char *)malloc(STACK_SIZE); //because the increase of stack address is from highaddress to low address stack += STACK_SIZE; retval = clone((void*)func,stack,clone_flag,(void *)&arg); printf("retval = %d\n",retval); return 1; } ~
二、线程库支持的用户线程
1、POSIX线程
POSIX线程包提供一组函数,用来创建,删除和同步同一进程内的线程,使用时需要加入头文件pthread.h, 编译时需要使用-pthread来链接线程库
2、线程的创建
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg); //tidp:要创建的线程的线程id //attr:为新线程定义不同的属性(如栈的大小) //start_rtn:指定执行的函数 //arg:传递给函数的参数
pthread_create与clone的区别在于:clone()创建的是一个内核支持的用户线程,对内核是可见的且由内核调度,而pthread_create创建一个线程库支持的用户线程,对内核不可见,由线程库调度;
线程的标识符:与进程类似,线程也有线程标识符,可通过pthread_self()获取;
#include <stdio.h> #include <pthread.h> #include <unistd.h> void *create(void *arg) { printf("new thread...\n"); printf("thread id = %u\n",(unsigned int)pthread_self()); printf("thread pid = %d\n",getpid()); return (void*)0; } int main() { pthread_t tid; int error; printf("Main thread is starting...\n"); error = pthread_create(&tid,NULL,create,NULL); if(error != 0) { printf("thread is not created...\n"); return -1; } printf("main pid = %d\n",getpid()); sleep(1); return 0; }
3、线程等待
int pthread_join(pthread_t thread,void **status); //pthread:指定等待的线程 //status:指向指针的指针,用于指定返回值 //函数返回值:0表示成功,非0表示失败
4、线程同步
(1)信号量
#inclued <semaphore.h> int sem_init(sem_t *sem,int pthread,unsigned int value); //初始化信号量 //sem:为指向信号量结构的一个指针 //pshared:不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享 //value:给出了信号量的初始值 int sem_wait(sem_t *sem); int sem_post(sem_t *sem); int sem_destroy(sem_t *sem);
可以参考 信号量-百度百科
(2)互斥量
#include<pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr); int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_destroy(pthread_mutex_t *mutex);
通过使用互斥量,使用两个线程同时读取两个文件并统计单词个数:
#include <stdio.h> #include <pthread.h> #include <ctype.h> #include <string.h> #include <stdlib.h> pthread_mutex_t counter_clock; int total_words = 0; void *count_words(void *f) { char *filename = (char *)f; FILE *fp; int c,prevc = '\0'; printf("file:%s\n",filename); if((fp = fopen(filename,"r")) != NULL) { while((c = getc(fp)) != EOF) { if(!isalnum(c) && isalnum(prevc)) { pthread_mutex_lock(&counter_clock); total_words++; pthread_mutex_unlock(&counter_clock); } prevc = c; } fclose(fp); } else { perror(filename); } return NULL; } int main(int argc,char *argv[]) { pthread_t thread1,thread2; void *thread_result1,*thread_result2; int error; if(argc != 3) { printf("Usage:%s file1 file2\n",argv[0]); exit(1); } printf("reading...\n"); error = pthread_create(&thread1,NULL,count_words,(void *)argv[1]); if(error != 0) { printf("create thread failed...\n"); return -1; } error = pthread_create(&thread2,NULL,count_words,(void *)argv[2]); if(error != 0) { printf("create thread failed...\n"); return -1; } pthread_join(thread1,&thread_result1); pthread_join(thread2,&thread_result2); printf("total words:%d\n",total_words); pthread_mutex_destroy(&counter_clock); return 0; }
5、线程终止
线程的正常退出包括以下几种
线程只是从启动例程返回,返回值是线程中的退出码;
线程被另一个线程终止;
线程自己调用pthread_exit()终止;
void pthread_exit(void *rval_prt); //rval_ptr:线程退出返回的指针;
相关文章推荐
- ubuntu sublime-text-3 3103 无法输入中文
- android2.3 --- Service Manager分析
- 商品住宅实行住宅质量保证书和住宅使用说明书制度的规定
- CSDN博客积分规则
- 正则表达式 验证输入为电话号码或手机
- 移动app安全测试
- VB.net版机房收费系统——VS报表制作及功能实现中的问题及解决办法(好学的代价=Bug)
- 第一章:权限管理基础
- iOS UITableView的用法
- 7Cable master
- Java ,== ,equals的区别
- IEEE制定的浮点数表示法
- 《深入了解计算机系统》第七章读书笔记
- MySQL相关问题总结
- <jQuery>首页图片切换/轮播
- vsftpd.conf:vsftpd配置文件
- Android右滑销毁Activity
- Android 播放音频文件
- ::在C++中是什么意思
- 常用查找算法 总结