进程与线程(二)
来源:互联网 发布:域名免费的 编辑:程序博客网 时间:2024/04/27 22:52
Linux中的线程机制十分特殊,从内核的角度来说并没有线程的概念,故没有为线程单独定义数据结构,通过clone()创建的Linux线程,仅被看做一个与其他进程共享某些资源的特殊进程而已;
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*8void *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:线程退出返回的指针;
- 进程与线程(二)
- Android进程与线程(二):线程
- 进程与线程(二)
- 进程与线程学习(二)
- 操作 python -- 进程与线程 (二)
- 进程与线程(二):线程的开启与挂起
- 进程管理——进程与线程(二)
- Android线程与进程(二)线程详解
- android进程与线程详解二:线程
- android进程与线程详解二:线程
- android进程与线程详解二:线程
- android进程与线程详解二:线程
- android进程与线程详解二:线程
- android进程与线程详解二:线程
- android进程与线程详解二:线程
- android进程与线程二:线程
- 【Linux之路】进程与线程(二)
- 《计算机操作系统》总结二(进程与线程)
- 正则表达式 验证输入为电话号码或手机
- android2.3 --- Service Manager分析
- ubuntu sublime-text-3 3103 无法输入中文
- [c++]继承 多态
- CSDN博客积分规则
- 进程与线程(二)
- 源码分析-Android中的消息机制详解
- Struts2文件上传与过滤
- Netty in Action (十) 第四章节 第三部分 Netty原生绑定的传输服务
- 最长回文:LeetCode:5. Longest Palindromic Substring
- 初步学习C++中的继承关系
- linux包括三个段“数据段”,“代码段”, “堆栈段”
- Android 属性系统 Property service 设定分析
- LeetCode之12---Integer to Roman