您的位置:首页 > 其它

线程的创建和控制

2016-04-22 18:22 375 查看
线程的定义:
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
各线程还共享以下进程资源和环境:
1. 文件描述符表
2. 每种信号的处理方式(SIG_IGN、 SIG_DFL或者自定义的信号处理函数)
3. 当前工作目录
4. 用户id和组id
但有些资源是每个线程各有一份的:
1. 线程id
2. 上下文,包括各种寄存器的值、程序计数器和栈指针
3. 栈空间
4. errno变量
5. 信号屏蔽字
6. 调度优先级
我们将要学习的线程库函数是由POSIX标准定义的,称为POSIX thread或者pthread。在Linux上线 程函数位于libpthread共享库中,因此在编译时要加上-lpthread选项。

线程创建:
相关函数:



返回值:成功返回0,失败返回错误号。在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的函数指针start_routine决 定。start_routine函数接收一个参数,是通过pthread_create的arg参数传递给它的,该
参数的类型为void *,这个指针按什么类型解释由调用者自己定义。
start_routine的返回值类型也是void *,这个指针的含义同样由调用者自己定义。 start_routine返回时,这个线程就退出了,其它线程 可以调用pthread_join得到start_routine的返回值,类似于父进程调用wait(2)得到子进程的退出 状态。
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

pthread_t tid;
void* thread_run(void* _val)
{
printf("%s:pid is :%d,tid is:%u\n", (char*)_val,(int)getpid(),(unsigned long long)pthread_self());
return NULL;
}

int main()
{
int err=pthread_create(&tid,NULL,thread_run,"other thread run");
if(err!=0)
{
printf("create thread error!info is:%s\n",strerror(err));
exit(err);
}
printf("main thread run:pid is:%d,tid is:%u\n",(int)getpid(),(unsigned long long)pthread_self());
sleep(1);
return 0;
}
运行结果:



分析:1、在Linux上,thread_t类型是一个地址值,属于同一进程的多个线程调用getpid(2)可以得到相同的进程号,而调用pthread_self(3)得到的线程号各不相同。
2、由于pthread_create的错误码不保存在errno中,因此不能直接用perror(3)打印错误信息,可以先用strerror(3)把错误码转换成错误信息再打印。
3、如果任意一个线程调用了exit或_exit,则整个进程的所有线程都终止,由于从main函数return也相当于调用exit,为了防止新创建的线程还没有得到执行就终止,我们在main函数return之前延 时1秒,这只是一种权宜之计,即使主线程等待1秒,内核也不一定会调度新创建的线程执行

线程终止:

1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
3. 线程可以调用pthread_exit终止自己。
线程等待:
1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
2. 如果thread线程被别的线程调用pthread_cancel异常终掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。
3. 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ptr参数
相关函数:










代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

void *thread1(void *_val)
{
printf("thread1 returning...\n");
return (void*)1;
}

void *thread2(void *_val)
{
printf("thread2 returning...\n");
pthread_exit( (void*)2);
}

void *thread3(void *_val)
{
while(1)
{
printf("pthread 3 is running,wait for be cancel...\n");
sleep(1);
}
return NULL;
}

int main()
{
pthread_t tid;
void *tret;
pthread_create(&tid,NULL,thread1,NULL);
pthread_join(tid,&tret);
printf("thread return,thread id is:%u,return code is:%d\n",(unsigned long)tid,(int)tret);

pthread_create(&tid,NULL,thread2,NULL);
pthread_join(tid,&tret);
printf("thread exit,thread id is:%u,exit code is:%d\n",(unsigned long)tid,(int)tret);

pthread_create(&tid,NULL,thread3,NULL);
sleep(3);
pthread_cancel(tid);
pthread_join(tid,&tret);
printf("thread return,thread id is:%u,cancel code is:%d\n",(unsigned long)tid,(int)tret);
return 0;
}
运行结果:




线程分离:
线程是可结合的( joinable)或者是分离的( detached) 。 一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(例如栈)是不释放的。 相反, 一个分离的线程是不能被其他线程回收或杀死的,它的存储器 资源在它终止时由系统自动释放。

线程默认情况下被创建成可结合的,为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收(调用pthread_join),要么通过调用pthread_detach被分离。调用pthread_join后,如果线程没有运行结束,调用者会被阻塞。
相关函数:




代码:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

void *thread_run(void *_val)
{
pthread_detach(pthread_self());
printf("%s\n",(char*)_val);
return NULL;
}

int main()
{
pthread_t tid;
int tret=pthread_create(&tid,NULL,thread_run,"thread1 run...");
if(tret!=0)
{
printf("create thread error!,info is:%s\n",strerror(tret));
return tret;
}

int ret=0;
sleep(1);
if(0==pthread_join(tid,NULL))
{
printf("pthread wait success!\n");
ret=0;
}
else
{
printf("pthread wait failed!\n");
ret=1;
}
return ret;
}
运行结果:


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  程序 寄存器 多线程