进程与线程(二)

来源:互联网 发布:域名免费的 编辑:程序博客网 时间: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);     returnvoid *)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:线程退出返回的指针;
0 0
原创粉丝点击