pthread_create()函数参数详解和传参的使用

题外话:

用的vscode编译的程序。发现一个问题,就是编译的时候提示没有gcc,但是应该是安装了的。打开命令端,输入gcc -v,提示没有gcc。
因为安装了qt。默认的就有gcc,所以就打开qt的安装路径下C:\Qt\Qt5.12.4\Tools\mingw730_64\bin,路径下文件如下图所示
在这里插入图片描述
然后直接把该路径添加到环境变量,就可以使用gcc 和g++了
贼有意思,gcc也能编译,g++也能编译。
在linux下通过gcc编译c程序,g++编译c++程序,另外就是也没有加-lpthread连接线程库就编译通过了。
sleep函数使用的头文件<unistd.h>也可以编译通过,也就是说,并没有使用windows的库。

在这里插入图片描述


正题:

pthread_create是UNIX环境创建线程函数
头文件 #include<pthread.h>
函数声明 int pthread_create(pthread_t*restrict tidp,const pthread_attr_t
restrict_attr,voidstart_rtn)(void),void *restrict arg);
返回值 若成功则返回0,否则返回出错编号 返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于制定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。 linux下用C开发多线程程序,Linux系统下的多线程遵循POSIX线程接口,称为pthread。 由 restrict 修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取。对对象的存取都限定于基于由 restrict 修饰的指针表达式中。 由 restrict 修饰的指针主要用于函数形参,或指向由 malloc() 分配的内存空间。restrict 数据类型不改变程序的语义。 编译器能通过作出 restrict 修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。 参数 第一个参数为指向线程标识符的指针。 第二个参数用来设置线程属性。 第三个参数是线程运行函数的起始地址。 最后一个参数是运行函数的参数。 另外,在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库 示例 打印线程 IDs

	#include <pthread.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <unistd.h>
  #include <string.h>
  pthread_t ntid;
  void printids(const char *s)
  {
  pid_t pid;
  pthread_t tid;
  pid = getpid();
  tid = pthread_self();
  printf("%s pid %u tid %u (0x%x)\n", s,
  (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
  } void *thr_fn(void *arg)
  {
  printids("new thread: ");
  return((void *)0);
  }
  int main(void)
  {
  int err;
  err = pthread_create(&ntid, NULL, thr_fn, NULL);
  if (err != 0)
  printf("can't create thread: %s\n", strerror(err));
  printids("main thread:");
  sleep(1);
  exit(0);
  }
  $ gcc main.c -lpthread
  $ ./a.out


向线程函数传递参数详解:

向线程函数传递参数分为两种:

(1)线程函数只有一个参数的情况:直接定义一个变量通过应用传给线程函数。

例子:

#include <iostream>
#include <pthread.h>
using namespace std;
pthread_t thread;
void fn(void *arg)
{
    int i = *(int *)arg;
    cout<<"i = "<<i<<endl;
    return ((void *)0);
}
int main()
{
    int err1;
    int i=10;
   err1 = pthread_create(&thread, NULL, fn, &i);
    pthread_join(thread, NULL);
}

2、线程函数有多个参数的情况:这种情况就必须申明一个结构体来包含所有的参数,然后在传入线程函数,具体如下:

例子:
首先定义一个结构体:



struct  parameter

{
  int size,
  int count;
};

然后在main函数将这个结构体指针,作为void *形参的实际参数传递

struct parameter arg;

通过如下的方式来调用函数:

pthread_create(&ntid, NULL, fn,& (arg));

函数中需要定义一个parameter类型的结构指针来引用这个参数

void fn(void *arg)
{
    int i = *(int *)arg;
    cout<<"i = "<<i<<endl;
    return ((void *)0);
}


void thr_fn(void *arg)
{
       struct parameter *pstru;
       pstru = ( struct parameter *) arg;
       然后在这个函数中就可以使用指针来使用相应的变量的值了。
}

**

具体实例

**
主要解决以下三个问题
1.普通传参(只传一个参数)
2.结构体传参(传多个参数)

  1. 普通传参(只传一个参数)
    函数功能介绍,主线程一个while循环,等待变量的值,如果等于10就打印一句话。新创建的线程首先拿到传递过来的参数,然后再给参数赋值(相当于主线程已经等到了要的值)
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
//int sum = 0;

void *test(void *arg)
{
    printf("arg= %d\n",*(int *)arg);
     //int sum = *(int *)arg;
     int temp_run=1;
     temp_run = *(int *)arg;
     printf("tem_run= %d\n",temp_run);
    *(int *)arg = 10;
     temp_run = *(int *)arg;
    //sum = sum + 1;
     while(temp_run){
         temp_run --;
         if(temp_run == 2)
            printf("tem_run= %d\n",temp_run);
     }
}

int main()
{
    pthread_t pthread_id;
    int sum = 0;//局部变量,在main函数中,main没有结束,就不会释放。main是一个进程吗?一次执行过程
    int run = 1;
    int time = 10;
    int ret = -1;
    /*if(pthread_create(&pthread_id,NULL,test,&sum) != 0)
        printf("create error\n");
    */
   ret = pthread_create(&pthread_id,NULL,test,&sum);
   printf("ret = %d\n",ret);
    while(run)
    {
       /* 
            if(sum != time)
            sum++;
        */
       if(sum == time)
       {
        printf("------run end------\n");
            run = 0;
       }
    }

    //pthread_create(&pthread_id,NULL,test,&sum);//在while循环后创建线程,能执行到创建这一句吗?
    //sleep(5);//没有打印出来线程里的消息,是因为主线程已经结束了。睡眠五秒可以解决。另外一般都是调用ptread_join()
    pthread_join(pthread_id,NULL);//阻塞等待当前线程
    printf("sum=%d,run=%d,time=%d\n",sum,run,time);
    pthread_exit(&pthread_id);//结束当前线程,释放私有资源
    return 0;

}

上述代码注意的问题
1.创建线程的的位置,如果run函数的起始值为1,是不能再while后创建线程的,因为走不到创建线程这个位置。如果起始值为0,是可以用上述代码的。不然要把注释部分打开,吧下边的创建关闭。另外线程一旦创建,就不会存在while循环卡住的问题了,在线程内部开while是照样可以运行下边的话。线程是个并行的关系
2、关于局部变量问题。在线程中为传入的参数赋值了,赋值的时候注意是直接给传入进来的指针赋值,而不是将指针的值拿到修改,此时修改了之后,并没有传递回去,除非是全局变量。如果传入的形参是全局变量是可以的。在这里发现main的局部变量就是相当于全局变量? 另外全局变量可能会被局部变量覆盖,第一次的时候发现在线程处理函数中给sum赋值的时候,提示未定义,就直接定义了一个sum,此时的sum和自己想要的sum并不是一个,这个是局部变量。使用的时候就算赋值,也只是操作的局部变量
3.另外线程创建的时候要注意调用线程回收ptread_join。不然主线程会提前结束的话,线程处理函数可能来不及运行完。去掉线程回收函数,会发现线程中的打印都没有来得及打印就结束了。线程结束后调用线程退出函数pthread_exit,完成线程资源的回收

2.结构体传参(传多个参数)
函数功能介绍:
创建线程的时候,传递一个结构体,然后子线程中打印传入结构体的值,然后再给传入的参数赋值,有两种方式,一种是结构体整个赋值,一种是值对其中一个成员赋值,只对一个成员赋值效率较低。

#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
//int sum = 0;
   typedef struct test
    {
        /* data */
        int test1;
        int test2;
    }TEST;
   
void *test(void *arg)
{
    //printf("arg= %d\n",*(int *)arg);
     //int sum = *(int *)arg;
    TEST *temp = (TEST *)arg; //强制类型转换,不加编译不过去
    temp->test1 = 10;
    temp->test2 = 111;
    printf("test1 = %d,test2 = %d\n",temp->test1,temp->test2);
  // (TEST *) arg->test1 = 10;//失败
    // arg->test1 = 10;//错误代码
  //  * (TEST *) arg.test1 = 10;//错误代码
  //  ((int *)(arg))->test1 = 10;//错误代码
    *( (int *) ( ( (TEST *) arg) -> test1 ) ) = 10;//成功,将参数转换成具体数据类型的指针,然后将指针成员转换成对应的具体数据类型,然后给其赋值。相对于下边的实现方法,贼卡,明显感觉处理速度慢
  //  *(TEST *)  arg = *temp;//成功,先给一个结构体指针赋值,在吧该结构体的赋值给参数结构体,记得类型转换。要加*(是内容的赋值,并不是地址赋值)
}

int main()
{
    pthread_t pthread_id;
    int run = 1;
    int time = 10;
    int ret = -1;
    TEST test_struct;
    /*if(pthread_create(&pthread_id,NULL,test,&sum) != 0)
        printf("create error\n");
    */
   ret = pthread_create(&pthread_id,NULL,test,&test_struct);
   printf("ret = %d\n",ret);
    while(run)
    {
       /* 
            if(sum != time)
            sum++;
        */
       if(test_struct.test1 == time)
       {
        printf("------run end------\n");
            run = 0;
       }
    }

    //pthread_create(&pthread_id,NULL,test,&sum);//在while循环后创建线程,能执行到创建这一句吗?
    //sleep(5);//没有打印出来线程里的消息,是因为主线程已经结束了。睡眠五秒可以解决。另外一般都是调用ptread_join()
    pthread_join(pthread_id,NULL);
    printf("run=%d,time=%d\n",run,time);
    pthread_exit(&pthread_id);
    return 0;

}

版权声明:本文为apanying原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。