2017-05-14 18:46:35 Sunird 阅读数 420

初学操作系统对于线程的知识了解是很重要的,因此我们借用对pthread库函数的一些小运用来加深对多线程的认识。
注:本实验在linux系统下进行。

“pthread.h”头文件无法在windows平台下直接引用,需要在编译器编译过程中自行添加,笔者测试用的是pthreads-w32-2-4-0-release.exe,有兴趣的读者可自行研究这里不作扩展。


涉及到的函数有:

pthread_create //用于创建一个新的线程

//pthread_create函数原型:
#include <pthread.h>
 int pthread_create(pthread_t *restrict tidp,
               const pthread_attr_t *restrict attr,
               void *(*start_rtn)(void),
               void *restrict arg);

 Returns: 0 if OK, error number on failure
  • pthread_t *restrict tidp ,tidp是指向一个线程ID的指针。
  • const pthread_attr_t *restrict attr:线程属性设置。
  • void *(*start_rtn)(void),第三个参数是一个指向函数指针,即线程运行函数的起始地址。新创建的线程从该函数的起始地址开始运行。
  • void *restrict arg:给执行函数传递参数参数
    返回值:
    若成功则返回0,否则返回出错编号。

由 restrict修饰的指针是最初唯一对指针所指向的对象进行存取的方法,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改,保证了代码的安全性。

pthread_jion//阻塞,等待线程结束

//pthread_jion函数原型
#include <pthread.h>
int pthread_join(pthread_t thread, 
              void **retval); 
Returns: 0 if OK, error number on failure

-pthread_t thread:线程ID。
-void **retval为一个用户定义的指针,它可以用来存储被等待线程的返回值。
返回值:
若成功则返回0,否则返回出错编号。

当我们需要所有线程都结束之后再对他们的结果进行统一操作时,就需要在主函数里加入阻塞函数,等待所有线程都结束后在进行后续操作。


实例:随机生成10万个浮点数,创建4个线程分别实现2.5万个浮点数之和最后完成10万个浮点数之和。比较多线程和单线程的计算时间。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <memory.h>
#include <sys/time.h>

#define Max_Set 100000
float ssum[Max_Set];
pthread_t thread[4];
float suma=0.0;
float sumb=0.0;
float sumc=0.0;
float sumd=0.0;
float sum=0.0;

void fullssum(float a[],int length)
{
    for(int i=0;i<length;i++)
    ssum[i]=rand()/(float)(RAND_MAX/10);

}


void *thread_a(void *in)
{
    printf("i am thread_a\n");
    for(int i=0;i<Max_Set/4;i++)
    {
        suma+=ssum[i];
    }
    printf("suma=====%f\n",suma);
    pthread_exit((void *)0);
}

void *thread_b(void *in)
{
    printf("i am thread_b\n");
    for(int i=Max_Set/4;i<Max_Set/2;i++)
        {
                sumb+=ssum[i];
        }
        printf("sumb=====%f\n",sumb);

    pthread_exit((void *)0);
}

void *thread_c(void *in)
{
        printf("i am thread_c\n");
        for(int i=Max_Set/2;i<Max_Set*3/4;i++)
        {
                sumc+=ssum[i];
        }
        printf("sumc=====%f\n",sumc);

        pthread_exit((void *)0);
}

void *thread_d(void *in)
{
        printf("i am thread_d\n");
        for(int i=Max_Set*3/4;i<Max_Set;i++)
        {
                sumd+=ssum[i];
        }
        printf("sumd=====%f\n",sumd);
        pthread_exit((void *)0);
}

int main()
{
    int temp;
    struct timeval start, end1,end2;

    //用随机数填满数组
    fullssum(ssum,Max_Set);
    //初始化线程ID
    memset(&thread ,0 ,sizeof(thread));
    //获取当前时间
    gettimeofday(&start,NULL);
    if((temp=pthread_create(&thread[0],NULL,thread_a,NULL))!=0)
    printf("error in thread_a\n");
    else
    printf("thread_a creat success!\n");
    if((temp=pthread_create(&thread[1],NULL,thread_b,NULL))!=0)
        printf("error in thread_b\n");
    else
        printf("thread_b creat success!\n");
     if((temp=pthread_create(&thread[2],NULL,thread_c,NULL))!=0)
        printf("error in thread_c\n");
     else
        printf("thread_c creat success!\n");
     if((temp=pthread_create(&thread[3],NULL,thread_d,NULL))!=0)
        printf("error in thread_d\n");
     else
        printf("thread_d creat success!\n");
    for(int i=0;i<4;i++)
    {
        if(thread[0]!=0)
        {   
        pthread_join(thread[0],NULL);
        printf("thread%d come to an end\n",i+1);
        }
    }
    //等待所有线程结束计算和
    printf("RESULT1=======%f\n",suma+sumb+sumc+sumd);
    //获取当前时间
    gettimeofday(&end1,NULL);
    int time1=1000000*(end1.tv_sec-start.tv_sec)+end1.tv_usec-start.tv_usec;
    //输出多线程计算用时
    printf("time1======%d\n",time1);
    for(int j=0;j<Max_Set;j++)
    {
        sum+=ssum[j];
    }
    printf("RESULT2=======%f\n",sum);
    gettimeofday(&end2,NULL);
    int time2=1000000*(end2.tv_sec-end1.tv_sec)+end2.tv_usec-end1.tv_usec;
    //输出单线程计算用时
    printf("time2======%d\n",time2);
}

使用gcc编译pthread库程序需要加 -lpthread
例如:gcc pthread.c -o thread -lpthread

2019-04-05 18:49:30 weixin_43784003 阅读数 536

实验二:线程的创建

来源:课件与源码

1.实验内容

  随机生成N组非负整数列表,然后创建N个线程,分别用N种不同的排序算法对列表进行排序。

  进入图形模式,沿垂直方向把屏幕分成N个区域,每个排序线程用一个区域,动态显示排序过程。

注:本实验不用自己编写系统调用函数,源码中已经写好,相关函数接口说明见本文最后。

2.实验步骤

Step1:

全局变量step=4; //使画线看起来有一定宽度
(1)在userapp/main.c中编写排序函数,我用了四种排序算法(冒泡、选择和、插入和希尔排序),每个线程使用一种。

①冒泡排序

//冒泡排序线程函数
void tsk_bubbleSort(void *p)
{  
     printf("This is bubbleSort_task foo with tid=%d\r\n",task_getid()); 
     int i,j,temp;
     int *arr = (int *)p;
     int y=  g_graphic_dev.YResolution/step

     for(i=0;i<y;i++)
{    
line(0, step*i, arr[i], step*i, RGB(255, 0, 0));
}        

//冒泡排序
for(i=0;i<y-1;i++)
{
   for(j=0;j<y-1-i;j++)
  {
    if(arr[j] > arr[j+1])//如果大于,则交换
            {
                temp = arr[j];
                line(0,step*j, arr[j],step*j, RGB(0, 0, 0));//清除原来的线
                arr[j] = arr[j+ 1];
                line(0,step*j, arr[j],step*j,RGB(255,0,0));//重新画线

                line(0, step*(j + 1), arr[j + 1],step*(j + 1), RGB(0, 0, 0));//清除原来的线
                arr[j+ 1] = temp;
                line(0,step*(j + 1), arr[j + 1],step*(j + 1), RGB(255, 0, 0));//重新画线
             }
   }
    nanosleep((const struct timespec[]){{0,10000000L}}, NULL);//睡眠1s
}
     task_exit(0);
}

②插入排序

//插入排序线程函数
void tsk_insertSort(void *p)
{  
     printf("This is insertSort_task foo with tid=%d\r\n",task_getid()); 
     int i,j,temp;    
     int*arr=(int*)p;    
     int x = g_graphic_dev.XResolution/4;
     int y=  g_graphic_dev.YResolution/step;

   //画排序前数组
for(i=0;i<y;i++)
{
    line(x, step * i,x+ arr[i],step* i, RGB(0, 255, 0));
}
//插入排序
for (i = 1; i <y; i++)//从第二个元素开始
{     
temp = arr[i];
    for (j = i - 1; j >= 0 && arr[j] > temp;j--)
    {
        line(x,step * (j + 1), x+arr[j + 1], step * (j + 1), RGB(0, 0, 0));//清除原来的线
        arr[j + 1] = arr[j];
        line(x,step * (j + 1), x+arr[j + 1], step * (j + 1), RGB(0,255, 0));//重新画线
    }

    line(x, step * (j + 1), x+arr[j + 1],step * (j + 1), RGB(0, 0, 0));//清除原来的线
    arr[j + 1] = temp;
    line(x, step* (j + 1), x+arr[j + 1], step * (j + 1), RGB(0, 255, 0));//重新画线
    nanosleep((const struct timespec[]){{0, 10000000L}}, NULL);
}
     task_exit(0);
}

③选择排序

//选择排序线程函数
void tsk_selectSort(void *p)
{  
     printf("This is selectSort_task foo with tid=%d\r\n",task_getid()); 
     int i,j,lowindex,temp;
     int*arr=(int*)p;
     int x = g_graphic_dev.XResolution / 4;
     int y=  g_graphic_dev.YResolution/step;

for(i=0;i<y;i++)
{
    line(2*x, step* i,2*x+arr[i], step* i, RGB(0, 0, 255));
}
//选择排序

for (i = 0; i < y - 1; i++)
{
    lowindex
= i;
    for (j = y - 1; j > i; j--)
        if (arr[j] < arr[lowindex])
            lowindex= j;
    if (lowindex != i)
{
        temp= arr[i];
        line(2 * x,step * i, 2* x + arr[i], step* i, RGB(0, 0, 0));//清除原来的线
        arr[i] = arr[lowindex];
        line(2* x, step* i, 2 * x + arr[i], step* i, RGB(0, 0, 255));//重新画线

        line(2* x, step*lowindex, 2 * x + arr[lowindex], step* lowindex, RGB(0, 0, 0));//清除原来的线
        arr[lowindex] =temp;
        line(2 * x, step * lowindex,2 * x + arr[lowindex], step* lowindex, RGB(0, 0, 255));//重新画线
    }

    nanosleep((const struct timespec[]){{0,10000000L}}, NULL);
}

task_exit(0);
}

④shell排序

    //shell排序线程函数
void tsk_shellSort(void *p)
{
        void shellSort(int *A, int n);
        printf("This is shellSort_task foo with tid=%d\r\n", task_getid());
        int i;
        int*arr = (int*)p;
        int x = g_graphic_dev.XResolution / 4;
        int y=  g_graphic_dev.YResolution / step;

        for (i = 0; i <y; i++)
        {
            line(3*x, step* i, 3*x + arr[i],step* i, RGB(255, 255, 255));            
        }    
        shellSort(arr,y);
        task_exit(0);
    }

void inssort(int* Arr,int k, int n, int incr)
{
    int i, j,temp;
    int x = g_graphic_dev.XResolution / 4; 
    for ( i = incr; i< n; i += incr)
    {
        for ( j = i; (j>= incr) && (Arr[j]<Arr[j - incr]); j-= incr)
        {
            temp= Arr[j];
            line(3* x, step*(j+k),3 * x + Arr[j], step*(j+k), RGB(0, 0, 0));//清除原来的线
            Arr[j] = Arr[j - incr];
            line(3* x, step* (j +k), 3 * x + Arr[j], step*(j+k), RGB(255, 255, 255));//重新画线
            
           line(3 * x, step* (j+k- incr), 3 * x + Arr[j - incr],step*(j+k - incr), RGB(0, 0, 0));//清除原来的线
            Arr[j - incr] =temp;
           line(3 * x, step* (j+k- incr), 3 * x + Arr[j - incr],step* (j+k - incr), RGB(255, 255, 255));//重新画线         
        }        
    }
}
void shellSort(int *Arr, int n)

{

    int i, j;

    void inssort(int *Arr, int k,int n, int incr);

    for (i = n / 2; i > 2; i /= 2)

        for (j = 0; j < i; j++)

    {

        inssort(&Arr[j],j, n - j,
i);

    nanosleep((const struct timespec[]){{0, 10000000L}}, NULL);}

        inssort(Arr,0, n,1);

}

注:
①这里的line函数用于画线,参数含义为:线两端横纵坐标和颜色RGB值。
②线的长度与数组中的整数大小对应,线越长表示值越大。注意每次画线之前要先擦除原来的线。
③若排序过程太快,可用nanosleep函数使线程睡眠,10000000L表示一秒钟。

另外,附打点方法:
pic1

Step2:在main函数中创建排序线程

(1)进入图形模式

    init_graphic(0x143);//进入图形页面:mode=0x143

(2)获取屏幕分辨率

 int x=g_graphic_dev.XResolution/4;//水平分辨率
 int y=g_graphic_dev.YResolution/step;//垂直分辨率

主要用于绘制排序过程,分割屏幕。本例中,随机数组的范围、长度以及画线都是根据屏幕分辨率来设定的。

(3)申请数组空间并随机赋值

srand(time(NULL));//设置随机数种子
//申请数组空间
int* arr_bubble=(int*)malloc(x*sizeof(int));
int* arr_insert=(int*)malloc(x*sizeof(int));
int* arr_select=(int*)malloc(x*sizeof(int));
int* arr_shell = (int*)malloc(x * sizeof(int));

int i;
for (i=0;i<y;i++)
{
     arr_bubble[i]=rand()%x;
     arr_insert[i]=rand()%x;
     arr_select[i]=rand()%x;  
     arr_shell[i] =rand()%x;
}

注:随机数需要用srand先播种,后使用rand生成。

(4)申请线程空间

//申请线程栈
unsigned int  stack_size = 1024*1024;   
unsigned char* stack_bubble=(unsigned char *)malloc(stack_size);   
unsigned char* stack_insert=(unsigned char *)malloc(stack_size);    
unsigned char* stack_select=(unsigned char *)malloc(stack_size);  
unsigned char* stack_shell=  (unsigned char *)malloc(stack_size);

(5)创建线程

task_create(stack_bubble+stack_size,&tsk_bubbleSort(void*)arr_bubble);
task_create(stack_insert+stack_size,&tsk_insertSort,(void*)arr_insert); 
task_create(stack_select+stack_size,&tsk_selectSort(void*)arr_select); 
task_create(stack_shell+stack_size, &tsk_shellSort, (void*)arr_shell);

注:
①线程函数只有一个void指针,可以将需要传入的参数定义成结构体,再进行强制类型转换。(结构体指针一定要先分配空间!)
②task_create函数的返回值是线程id,本例中并不需要。

(6)退出图形模式

    while(1)
        ;
    exit_graphic();//退出图形模式
    task_exit(0);//退出线程
}

实现效果:

在这里插入图片描述

3.问题总结

(随时更新)

附:系统调用接口说明

在这里插入图片描述

完整代码下载:https://download.csdn.net/download/weixin_43784003/11090897

PS:刚开始做实验很可能因为变量和函数的定义没搞懂而不知道从何下手,希望这几篇文章能够帮助你理清思路。对实验的理解有任何问题都欢迎给我留言,但请不要直接将本文用于作业提交。一是代码的查重不能通过,二也希望大家都能通过这门课真正地学到知识。

2017-05-27 22:25:42 weiyongle1996 阅读数 469

一、线程的概念

      线程可以理解为小型、轻型的进程,它是包含在进程中的,线程和进程的具体区别如下:

调度:一个进程可以有多个线程。线程作为CPU调度和分派的基本单位,进程则作为资源分配的基本单位。同一进程中的线程切换不会引起进程切换,从而避免昂贵的系统调用,但是从一个进程的线程切换到另一个进程的线程时,依然会引起进程切换。

切换时的系统开销:由于在创建或者撤销进程时,系统都要为之分配或回收资源,因此,操作系统所付出的开销将显著地大于创建或者撤消线程的开销。在进程切换时,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置,而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作。同时,由于同一个进程中的多个线程具有相同的地址空间,致使它们之间的同步和通信的实现也变得比较容易。

占用的资源:进程是拥有系统资源的一个独立的单位,它可以拥有自己的资源。线程自己一般不拥有资源(有一点必不可少的资源,包括程序计数器,一组寄存器和栈等),但它可以访问其隶属进程的资源,如进程代码段,数据段以及系统资源(已打开的文件,I/O设备等)。

单线程进程与多线程进程区别如下:

多线程的优点

  1. 响应度高(Responsiveness):即使其部分阻塞或执行较冗长操作,该程序仍能继续执行,从而增加了对用户的相应程度。

  2. 资源共享(Resource Sharing):线程默认共享它们所属进程的内存和资源。代码和数据共享的优点是它允许一个应用程序在同一地址空间有多个不同的活动线程。

  3. 经济(Economy):进程创建所需要的内存和资源的分配比较昂贵。由于线程能共享它们所属进程的资源,所以创建和切换线程会更为经济。

  4. 可拓展性(Scalability):多线程的优点之一是能充分使用多处理器体系结构。以便每个进程能并行运行在不同的处理器上。不管有多少CPU,单线程进程只能运行在一个CPU上,在多CPU上使用多线程加强了并发功能。

二、多线程模型

     有两种不同的方法来提供线程支持:用户层的用户线程(User Threads)和内核层的内核线程。用户线程受内核支持,而无需内核管理;而内核线程由操作系统支持和管理。事实上所有当代操作系统都支持内核线程。

用户线程与内核线程具有的关系如下:

1.多对一模型:多对一模型将许多用户级线程映射到一个内核线程。线程管理由线程库在用户空间进行的,因而效率比较高。但是如果一个线程执行了阻塞系统调用,那么整个线程会阻塞。因为任意时刻只能有一个线程能够访问内核,多个线程不能并行运行在多处理器上。

2.一对一模型:一对一模型每个用户线程映射到一个内核线程。该模型在一个线程执行阻塞系统调用时,能允许另一个线程继续执行。它也允许多个线程能并行运行在多处理器系统上,这种模型的唯一缺点是每创建一个用户线程就会创建一个相应的内核线程。由于创建内核线程的开销会影响应用程序的性能,所以这种模型的绝大多数实现限制了操作系统所支持的线程数量。

3.多对多模型:多对多模型多路复用了许多用户线程到同样数量或更小数量的内核线程上。多对多模型没有这两者的缺点:开发人员可创建任意多的用户线程,并且相应内核线程能在多处理器系统上并发执行。而且当一个线程执行阻塞系统调用时,内核能调度另一个线程来执行。

参考博客:http://blog.csdn.net/u013007900/article/details/49964515

2017-12-24 14:08:14 adminpd 阅读数 1173

一、实验目的

加深对进程概念的理解,明确进程与线程的区别。
掌握Linux进程创建和撤销的方法,进一步认识并发执行的实质。
了解多线程的程序设计方法。

二、实验项目内容

多进程和多线程
 1号进程创建2,3号两个进程
 2号进程创建两个线程Thread1,Thread2
 Thread1:求(1~n)之间的素数
 Thread2:生成Fibonacci序列
 3号进程创建4,5号两个进程
 4号进程执行系统命令,ls,ps,cp等
 5号进程执行一个用户编写的可执行文件
 每个进程输出自己的进程ID和父进程的进程ID,观察分析,并画出程序的进程树结构。

三、实验程序代码:

#include <stdio.h>
#include <math.h>
#include <sys/types.h>  
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

/**
* Attention to add -lpthread and -lm when compile
* eg : gcc process.c -lpthread -lm -o process
*/

//The thread to find the prime number between (1~n)
void *MyThread1(void* arg)
{
    int n;
    //Get the resolve range
    printf("input the value of n:\n");
    scanf("%d",&n);
    printf("the prime number between 1~%d is:\n",n);

    for(int m=2;m<=n;m++)
    {
        if (m<=3)
        {
            printf("%4d",m);
            continue;  
        }

       int k=sqrt(m);  
       for(int i=2; i<=k; i++)
       {
            // printf("m: %f\n",k);
            if(m%i==0) 
                break;  
            if(i>=k) 
                printf("%4d",m);  
       }
    }

    printf("\n thread1 exit!\n");
    pthread_exit(0);
}

//The thread to generate Fibonacci sequences
void *MyThread2(void* arg)
{
    int fib0=0,fib1=1,fib2,i,N;
    printf("input fib value N:\n");
    scanf("%d",&N);
    printf("the fib sequences as following:\n");
    for (int i = 0; i < N; i++)
    {
        if (i==0)
        {
            printf("0");
        }
        else if (i==1)
        {
            printf("1");
        }
        else
        {
            fib2=fib0+fib1;
            printf("%d",fib2 );
            fib0=fib1;
            fib1=fib2;
        }
    }
    printf("\n thread2 exit!\n");
    pthread_exit(0);
}

//No.2 process create two threads
int createThread()
{
    int ret1=0,ret2=0;
    //Define the id of thread
    pthread_t id1,id2;
    //Create thread1
    ret1=pthread_create(&id1,NULL,MyThread1,NULL);
    if (ret1)
    {
        printf("Create pthread error!\n");
        return 1;
    }
    //Create thread2
    ret2=pthread_create(&id2,NULL,MyThread2,NULL);
    if (ret2)
    {
        printf("Create pthread error\n");
        return 1;
    }

    //Mainthread wait for childthread
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);

    printf("main thread exit!\n");
    return 0;
}

//The Function of N0.4 and No.5
void childProcessfunc(int i)
{
    switch(i)
    {
        case 4:
            printf("\nThis is NO.4 process, ID is  %d, parent ID is %d, will create 2 thread\n",getpid(),getppid());
            printf("\nExcute system command ls:\n");
            system("ls");
            printf("\nExcute system command ps:\n");
            system("ps");
            printf("\nExcute system command cp:\n");
            system("cp sayhello.c sayhello.cpp");

            break;
        case 5:
            printf("\nThis is NO.5 process, ID is  %d, parent ID is %d, will create 2 thread\n",getpid(),getppid());
            printf("\nCarray out executable program:\n");
            system("./sayhello");
            break;
    }
    exit(0);
}

//No.3 process create two child process, N0.4 and No.5
int createProcess()
{
    int i;
    for (int i = 4; i <= 6; i++)
    {
        pid_t child=fork();
        //create process failed
        if (child==-1)    
        {
            printf("Error hanppened in fork function!\n");
            return 0;
        }
        //exert function when success
        else if(child==0)
        {
            childProcessfunc(i);
        }
    }

    for (int i = 0; i < 2; i++)
    {
        //Parent process waits child process
        pid_t tempPid=wait(NULL);
        printf("The process %d exit\n", tempPid);
    }

    return 0;
}

//The Function of N0.2 and No.3
void mainProcessfunc(int i)
{
    switch(i)
    {
        case 2:
            printf("\nThis is NO.2 process, ID is  %d, parent ID is %d, will create 2 thread\n",getpid(),getppid());
            createThread();
            break;
        case 3:
            printf("\nThis is NO.3 process, ID is  %d, parent ID is %d, will create 2 thread\n",getpid(),getppid());
            createProcess();
            break;
    }
    exit(0);
}

int main()
{
    int i;
    //Create two child process, No.2 and No.3
    for (int i = 2; i < 4; i++)
    {
        pid_t child=fork();
        if (child==-1)
        {
            printf("Error happened in fork function!\n");
            return 0;
        }
        else if(child==0)
        {
            // printf("process Id is %d:\n",getpid());
            mainProcessfunc(i);
        }
    }
    for (int i = 0; i < 2; i++)
    {
        //Parent process waits child process
        pid_t tempPid=wait(NULL);
        printf("\nThe process %d exit\n", tempPid);
    }
    //Root process exit
    printf("\nThe No.1 root process Id is %d exit\n",getpid());

    return 0;
}
注:在编译命令中添加-lpthread和 -lm ,-lpthread是表示要连接到pthread的库是这里省略的lib,因为在求素数算法中使用math库中sqrt函数,需要用到math.h,则加上 -lm。

四、实验结果

这里写图片描述

2019-04-04 16:26:09 luweiming123 阅读数 361

1.创建线程

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

/* 声明结构体 */
struct member
{
    int num;
    char *name;
};     

/* 定义线程pthread */
static void * pthread(void *arg)       
{
    struct member *temp;
    
    /* 线程pthread开始运行 */
    printf("pthread start!\n");
    
    /* 令主线程继续执行 */
    sleep(2);
    
    /* 打印传入参数 */
    temp = (struct member *)arg;      
    printf("member->num:%d\n",temp->num);
    printf("member->name:%s\n",temp->name);
    
    return NULL;
}

/* main函数 */
int main(int agrc,char* argv[])
{
    pthread_t tidp;
    struct member *b;

    /* 为结构体变量b赋值 */
    b = (struct member *)malloc(sizeof(struct member));           
    b->num=1;
    b->name="mlq";              

    /* 创建线程pthread */
    if ((pthread_create(&tidp, NULL, pthread, (void*)b)) == -1)
    {
        printf("create error!\n");
        return 1;
    }
    
    /* 令线程pthread先运行 */
    sleep(1);
    
    /* 线程pthread睡眠2s,此时main可以先执行 */
    printf("mian continue!\n");
    
    /* 等待线程pthread释放 */
    if (pthread_join(tidp, NULL))                  
    {
        printf("thread is not exit...\n");
        return -2;
    }
    
    return 0;
}

2.撤销线程

Linux线程可以取消其他线程,被取消的线程会被退出
线程本身可以设置不被其他线程取消

把线程状态设置为PTHREAD CANCEL-DISABLE的实例代码:

#include <pthread.h>
#include <stdio.h>
#include <string.h>
 
pthread_t tid1, tid2, tid3;
 
void* th_reader1(void *p)
{
	int i = 1;
	int oldstate = -1;
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
    for(; i <= 5; i++)
	{
		printf("func[%s]: 第 %d 秒\n", __FUNCTION__, i);
		sleep(1);
	}
	pthread_exit( (void *)0 );
}
 
int main()
{
    void *ret1, *ret2, *ret3;		
	
    printf("start thread reader 1\n");
    pthread_create(&tid2, NULL, th_reader1, NULL);  //创建 读 线程1
    
    sleep(2);
    pthread_cancel(tid2);  //发送取消信号
	
    pthread_join(tid2, &ret2);
 
    return 0;
}

运行结果

# ./a.out 
start thread reader 1
func[th_reader1]: 第 1 秒
func[th_reader1]: 第 2 秒
func[th_reader1]: 第 3 秒
func[th_reader1]: 第 4 秒
func[th_reader1]: 第 5 秒

把线程状态设置为PTHREAD CANCEL-DISABLE后,再设置为PTHREAD-CANCEL-ENABLE的实例代码:

#include <pthread.h>
#include <stdio.h>
#include <string.h>
 
pthread_t tid1, tid2, tid3;
 
void* th_reader1(void *p)
{
	int i = 1;
	int oldstate = -1;
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
    for(; i <= 5; i++)
	{
		printf("func[%s]: 第 %d 秒\n", __FUNCTION__, i);
		sleep(1);
		if(4 == i)
		{
			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
			printf("thread cancel PTHREAD-CANCEL-ENABLE \n");
			pthread_testcancel();						
		}
	}
	pthread_exit( (void *)0 );
}
 
int main()
{
    void *ret1, *ret2, *ret3;		
	
    printf("start thread reader 1\n");
    pthread_create(&tid2, NULL, th_reader1, NULL);  //创建 读 线程1
    
    sleep(2);
    pthread_cancel(tid2);//发送取消信号
	
    pthread_join(tid2, &ret2);
 
 
    return 0;
}

运行结果:

运行结果:

# ./a.out 
start thread reader 1
func[th_reader1]: 第 1 秒
func[th_reader1]: 第 2 秒
func[th_reader1]: 第 3 秒
func[th_reader1]: 第 4 秒
thread cancel PTHREAD-CANCEL-ENABLE 

3.终止线程

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

void *func1(void * f1)

{

    puts("我是第一个线程!我采用return的方式结束自己。");

    return (void*)770880;

}

void *func2(void * f2)

{

    puts("我是第二个线程!我采用pthread_exit的方式结束自己。");

    pthread_exit((void*)1314);

}

void *func3(void * f3)

{

    puts("我是第三个线程!我采用pthread_cancel的方式结束自己。");

    while (1)//可能会发生线程执行完但是主线程还没有开始调用pthread_cancel函数。

        pthread_testcancel();//主动设置取消点

    return (void*)520;

}

int main(void)

{

    pthread_t pth[3];

    void *i;

    pthread_create((pth + 0), NULL, func1, NULL);

    pthread_join(pth[0], (void**)&i);

    printf("线程一的退出状态:i = %d.\n", (int)i);

    pthread_create((pth + 1), NULL, func2, NULL);

    pthread_join(pth[1], (void**)&i);

    printf("线程二的退出状态:i = %d.\n", (int)i);

    pthread_create((pth + 2), NULL, func3, NULL);

    pthread_cancel(pth[2]);//杀死

    pthread_join(pth[2], (void**)&i);

    printf("线程三的退出状态:i = %d.\n", (int)i);

    return 0;

}

4.挂起线程

/*
*主线程创建子线程(当前子线程为stop停止状态),5秒后主线程唤醒子线程,
*10秒后主线程挂起子线程。15秒后主线程再次唤醒子线程,20秒后主线程执行完毕,
*等待子线程退出。
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
 
#define	RUN 	1
#define STOP	0
 
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 
int status = STOP;
 
void *thread_function(void)
{
	static int i = 0;
	while(1)
	{
		pthread_mutex_lock(&mut);
		while(!status)
		{
			pthread_cond_wait(&cond, &mut);
		}
		pthread_mutex_unlock(&mut);
		printf("child pthread %d\n", i++);
		if (i == 20)
		{
			break;
		}
		sleep(1);
	}
}
 
void thread_resume()
{
	if (status == STOP)
	{
		pthread_mutex_lock(&mut);
		status = RUN;
		pthread_cond_signal(&cond);
		printf("pthread run!\n");
		pthread_mutex_unlock(&mut);
	}
	else
	{
		printf("pthread run already\n");
	}
}
 
void thread_pause()
{
	if (status == RUN)
	{
		pthread_mutex_lock(&mut);
		status = STOP;
		printf("thread stop!\n");
		pthread_mutex_unlock(&mut);
	}
	else
	{
		printf("pthread pause already\n");
	}
}
 
int main()
{
	int err;
	static int i = 0;
	pthread_t child_thread;
	
	if (pthread_mutex_init(&mut, NULL) != 0)
	{
		printf("mutex init error\n");
	}
	if (pthread_cond_init(&cond, NULL) != 0)
	{
		printf("cond init error\n");
	}
	
	err = pthread_create(&child_thread,NULL,(void *)thread_function,NULL);
	if (err != 0)
	{
		printf("can't create thread:%s\n", strerror(err));
	}
	
	while(1)
	{
		printf("father pthread %d\n", i++);
		sleep(1);
		if (i == 5)
		{
			thread_resume();
		}
		if (i == 10)
		{
			thread_pause();
		}
		if (i == 15)
		{
			thread_resume();
		}
		if (i == 20)
		{
			break;
		}
	}
	if (0 == pthread_join(child_thread, NULL))
	{
		printf("child thread is over\n");
	}
	
	return 0;
}

5.关闭句柄

#include <stdio.h>
#include <string.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
int status;
if(!(pid= fork())){
printf("Hi I am child process!\n");
sleep(10);
return 0;
}
else{
printf("send signal to child process (%d) \n",pid);
sleep(1);
kill(pid ,SIGABRT); 
wait(&status);
if(WIFSIGNALED(status))
printf("chile process receive signal %d\n",WTERMSIG(status));
}
return 0;
}

运行结果:

send signal to child process(3170)
Hi I am child process!
child process receive signal 6
没有更多推荐了,返回首页