一 、# 线程的使用学习pthread_create函数详解 #原文出处
一、pthread_create函数:
1、简介:pthread_create是UNIX环境创建线程的函数
2、头文件:#include <pthread.h>
3、函数声明:
int pthread_create(pthread_t* restrict tidp,const pthread_attr_t* restrict_attr,void* (*start_rtn)(void*),void *restrict arg);
4、输入参数:(以下做简介,具体参见实例一目了然)
(1)tidp:事先创建好的pthread_t类型的参数。成功时tidp指向的内存单元被设置为新创建线程的线程ID。
(2)attr:用于定制各种不同的线程属性。APUE的12.3节讨论了线程属性。通常直接设为NULL。
(3)start_rtn:新创建线程从此函数开始运行。无参数是arg设为NULL即可。
(4)arg:start_rtn函数的参数。无参数时设为NULL即可。有参数时输入参数的地址。当多于一个参数时应当使用结构体传入。(以下举例)
5、返回值:成功返回0,否则返回错误码。
6、说明。
传递参数的时候传地址: pthread_create(&ntid, NULL, thr_fn, ¶m1);
线程函数的第一句通常是获取传入参数:Param tmp = *(Param *)arg;
举例如下:
二、不向线程函数传递参数:
#include "apue.h"
#include <pthread.h>
#include "apueerror.h"
#include <iostream>
#include <string>
using namespace std;
pthread_t ntid;
void printids(const char *s){
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %lu tid %lu (0x%lx)\n", s, (unsigned long)pid,
(unsigned long)tid, (unsigned long)tid);
}
void *thr_fn(void *arg){
cout << "----enter sub thread--------" << endl;
printids("new thread: ");
cout << "Change to C++ code!!" << endl;
cout << "----exit from sub thread----" << endl;
return((void *)0);
}
int main(void){
int err;
//第四个参数为NULL,说明没有向线程函数传参数。
err = pthread_create(&ntid, NULL, thr_fn, NULL);
if (err != 0)
err_exit(err, "can't create thread");
printids("main thread:");
sleep(1);
exit(0);
}
三、向线程函数传递一个参数:
#include "apue.h"
#include <pthread.h>
#include "apueerror.h"
#include <iostream>
#include <string>
using namespace std;
pthread_t ntid;
void printids(const char *s){
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %lu tid %lu (0x%lx)\n", s, (unsigned long)pid,
(unsigned long)tid, (unsigned long)tid);
}
struct Param {
int a;
int b;
int c;
};
void *thr_fn( void *arg ) {
cout << "----enter sub thread--------" << endl;
int tmp = *(int *)arg;
cout << "tmp=" << tmp << endl;
printids("new thread: ");
cout << "Change to C++ code!!" << endl;
cout << "----exit from sub thread----" << endl;
return((void *)0);
}
int main(void){
int err;
int num = 123;
//向线程函数传入一个参数。
err = pthread_create(&ntid, NULL, thr_fn, &num);
if (err != 0)
err_exit(err, "can't create thread");
printids("main thread:");
sleep(1);
exit(0);
}
四、向线程函数传递两个或以上的参数
#include "apue.h"
#include <pthread.h>
#include "apueerror.h"
#include <iostream>
#include <string>
using namespace std;
pthread_t ntid;
void printids(const char *s){
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %lu tid %lu (0x%lx)\n", s, (unsigned long)pid,
(unsigned long)tid, (unsigned long)tid);
}
struct Param {
int a;
int b;
int c;
};
void *thr_fn(void *arg) {
cout << "----enter sub thread--------" << endl;
Param tmp = *(Param *)arg;
cout << "tmp.a=" << tmp.a << endl;
cout << "tmp.b=" << tmp.b << endl;
cout << "tmp.c=" << tmp.c << endl;
printids("new thread: ");
cout << "Change to C++ code!!" << endl;
cout << "----exit from sub thread----" << endl;
return((void *)0);
}
int main(void){
int err;
int num = 123;
Param param1;
param1.a = 11;
param1.b = 22;
param1.c = 33;
//通过结构体向线程函数传入多个参数
err = pthread_create(&ntid, NULL, thr_fn, ¶m1);
if (err != 0)
err_exit(err, "can't create thread");
printids("main thread:");
sleep(1);
exit(0);
}
二、 #pthread_join()与pthread_detach()详解#
前言:
1.linux线程执行和windows不同,pthread有两种状态joinable状态和unjoinable状态,如果线程是joinable状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符(总计8K多)。只有当你调用了pthread_join之后这些资源才会被释放。若是unjoinable状态的线程,这些资源在线程函数退出时或pthread_exit时自动会被释放。
2.unjoinable属性可以在pthread_create时指定,或在线程创建后在线程中pthread_detach自己, 如:pthread_detach(pthread_self()),将状态改为unjoinable状态,确保资源的释放。或者将线程置为 joinable,然后适时调用pthread_join.
3.其实简单的说就是在线程函数头加上 pthread_detach(pthread_self())的话,线程状态改变,在函数尾部直接 pthread_exit线程就会自动退出。省去了给线程擦屁股的麻烦。
eg:
pthread_t tid;
int status = pthread_create(&tid, NULL, ThreadFunc, NULL);
if(status != 0)
{
perror("pthread_create error");
}
pthread_detach(tid);
一:pthread_join()
(1)pthread_join()即是子线程合入主线程,主线程阻塞等待子线程结束,然后回收子线程资源。
(2)函数说明
1)头文件 : #include <pthread.h>
2)函数定义: int pthread_join(pthread_t thread, void **retval);
3)描述 :pthread_join()函数,以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。
4)参数 :thread: 线程标识符,即线程ID,标识唯一线程。retval: 用户定义的指针,用来存储被等待线程的返回值。
5)返回值 : 0代表成功。 失败,返回的则是错误号。
(3)实例
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
void *thread_function(void *arg)
{
int i;
for ( i=0; i<8; i++)
{
printf("Thread working...! %d \n",i);
sleep(1);
}
return NULL;
}
int main(void)
{
pthread_t mythread;
if ( pthread_create( &mythread, NULL, thread_function, NULL) )
{
printf("error creating thread.");
abort();
}
if ( pthread_join ( mythread, NULL ) )
{
printf("error join thread.");
abort();
}
printf("thread done! \n");
exit(0);
}
三、##define和#ifdef的使用#
之前没有写过什么大工程,所以没有怎么关注过条件编译。今天在看代码的时候发现里面用到了#define和#ifdef来调试代码。于是就看了一下。顺便再做个笔记。
先介绍一下条件编译:
条件编译是根据实际定义的宏(可以认为是某一类条件)进行代码静态编译的手段。可以根据表达式的值或者某个特定宏是否被定义来确定编译条件。
在看几个预编译指令(预编译指令很多,这次只介绍用到的三个):
#define 定义一个预处理宏
#undef 取消宏的定义
#ifdef 判断某个宏是否被定义,若已定义,执行随后的语句
#else 与#if、#ifdef、#ifndef对应,若这些条件不满足,则执行#else之后的语句,相当于C中的else
#endif 是#if、#ifdef、#ifndef这些条件命令结束的标志
下面看一个很简单的条件编译例子:
#include<stdio.h>
#define CONDITION_1
int main(int argc, char **argv)
{
#ifdef CONDITION_1
printf("CONDITION_1!\n");
#else
printf("no CONDITION_1!\n");
#endif
return 0;
}
##if 0 或 #if 1(C语言注释)#
C语言注释有三种方法
常见的方法有:1)单行注释: //
2)多行注释: /* */
今天我想和初学者来聊聊一种相对不那么熟悉的C语言注释方法:利用条件编译注释代码。
3)#if 0 或 #if 1注释:
当屏蔽掉大块代码时,使用"#if 0"比使用"/**/"要好。(因为用"/**/"做大段的注释时,需要防止被注释掉的代码段中有嵌套的"/**/",一旦出现"/**/"嵌套"/**/"的情况,会导致你注释掉的代码区域并不是你想要的区域范围)
情况一:常见的一中,如有一段不想要的代码,可以直接用"#if 0 ... #endif"形式来注释,效果等同于"/**/"
#if 0
...程序段...
#endif
情况二:选择结构的条件编译。(如果常量为真【非0,随便什么数字,只要不是0】,就执行程序段1,否则执行程序段2。)
#if 常量
...程序段1...
#else
...程序段2...
#endif
情况三:嵌套情况。(如果常量a为真【非0,随便什么数字,只要不是0】,就执行程序段1。当常量a为0且常量b为真时,执行程序段2;当常量a为0且常量b为0时,执行程序段3)
#if 常量a
...程序段1...
#else
#if 常量b
...程序段2...
#else
...程序段3...
#endif
#endif