//!>
这是线程的入口函数
{
printf("The
Current process is: %d \n",
getpid());
//!>
当前进程ID
printf( "The
Current thread id : %d \n", (unsigned)pthread_self()
);
//!> 注意此处输出的子线程的ID
}
int main( )
{
pthread_t
t;
int
t_id;
t_id =
pthread_create( &t, NULL, print_id, NULL
);
//!> 简单的创建线程
if( t_id !=
0 )
//!>
注意创建成功返回0
{
printf("\nCreate thread error...\n");
exit(
EXIT_FAILURE );
}
sleep( 1
);
printf("\nThe Current process is: %d \n",
getpid());
//!>
当前进程ID
printf( "The
Main thread id : %d \n", (unsigned)pthread_self()
);
//!> 注意输出的MAIN线程的ID
return
0;
}
2.测试线程的创建和退出
#include
#include
#include
#include
void * entrance_1( void * arg
)
//!> 第一个创建的线程的入口函数
{
printf( "
thread 1 id == %d , run now ... \n", ( unsigned )pthread_self()
);
sleep( 3
);
return ( (
void * ) 1 );
}
void * entrance_2( void * arg
)
//!> 第二个创建的线程的入口函数
{
printf( "
thread 2 id == %d , run now ... \n", ( unsigned )pthread_self()
);
sleep( 3
);
return ( (
void * ) 2 );
}
int main( )
{
pthread_t
t1 =
-1;
//!> 最好是初始化:因为下面的pthread_join是需要判断是否成功在输出的
pthread_t
t2 =
-1;
int
tid1;
int
tid2;
void
*
ret;
tid1 =
pthread_create( &t1, NULL, entrance_1, NULL
);
//!> 简单的创建线程
tid2 =
pthread_create( &t2, NULL, entrance_2, NULL
);
if( tid1 !=
0 || tid2 != 0
)
//!>
创建线程失败
{
printf(
"Create thread error...\n" );
exit(
EXIT_FAILURE );
}
if( t1 != -1
)
//!> 也就是线程还没有结束
{
if (
pthread_join( t1, &ret ) == 0
)
//!> join success
{
printf( "
thread 1 get the return of pthread_join == %d \n", 2 );/ )
{
pthread_mutex_init( &mutex, NULL
);
//!> 初始化为默认的互斥锁
printf("主函数:创建2个子线程...\n");
create_two_thread();
//!> 创建2个线程
printf("主函数:等待线程完成任务...\n");
wait_two_thread();
//!> 等待线程完成任务
//!> 线程任务完成才可以执行下面代码
printf("线程任务完成...\n");
printf("Num == %d \n\n", num);
return 0;
}
4.双线程处理:冒泡排序算法
//
双线程处理冒泡排序(多线程也一样)
//
实现从“小”--->“大”排序
#include
#include
#include
#include
int g_arr[] = { 10, 23, 12, 34, 5, 29, 90, 9, 78, 44
};
//!> 全局的要排序的数组
pthread_t
thread[2];
//!> 两个线程
pthread_mutex_t
mutex;
//!> 互斥锁
int
g_i =
0;
//!> 全局的剩余排列次数
//!> 打印数组
void print_array()
{
int i;
for( i = 0;
i < 10; i++ )
{
printf( " %d
", g_arr[i] );
}
printf("\n");
}
//!> 交换元素
void swap_elem( int * a, int * b )
{
int
temp;
temp =
*a;
*a =
*b;
*b =
temp;
}
//!> 线程1入口函数
void * entrance_1( void * arg )
{
int j;
for( g_i =
0; g_i < 10; g_i++
)
//!> 外层循环
{
pthread_mutex_lock( &mutex
);
//!> 加锁
printf(
"线程1后台执行排序...\n" );
for( j = 0;
j < ( 10 - g_i - 1 ); j++
)
//!> 内层循环
{
if( g_arr[j]
> g_arr[j+1] )
{
swap_elem(
&g_arr[j], &g_arr[j+1] );
}
}
pthread_mutex_unlock( &mutex
);
//!> 解锁
sleep( 1
);
}
}
//!> 线程2入口函数
void * entrance_2( void * arg )
{
int j;
for( g_i =
0; g_i < 10; g_i++
)
//!> 外层循环
{
pthread_mutex_lock( &mutex
);
//!> 加锁
printf(
"线程2后台执行排序...\n" );
for( j = 0;
j < ( 10 - g_i - 1 ); j++
)
//!> 内层循环
{
if( g_arr[j]
> g_arr[j+1] )
{
swap_elem(
&g_arr[j], &g_arr[j+1] );
}
}
pthread_mutex_unlock( &mutex
);
//!> 解锁
sleep( 2
);
}
}
//!> 创建2个线程
void create_two_thread()
{
memset(
&thread, 0, sizeof( thread )
);
//!> 初始化为0(作为下面的判断进程是否创建OK依据)
if( (
pthread_create( &thread[0], NULL, entrance_1, NULL
) ) == 0 )
{
printf("线程1创建OK ...\n");
}
else
{
printf("线程1创建Error ...\n");
exit(
EXIT_FAILURE );
}
if( (
pthread_create( &thread[1], NULL, entrance_2, NULL
) ) == 0 )
{
printf("线程2创建OK ...\n");
}
else
{
printf("线程2创建Error ...\n");
exit(
EXIT_FAILURE );
}
}
//!> 线程执行与等待
void do_and_wait()
{
if(
thread[0] != 0 )//!>
由于在create_two_thread中初始化=0,if床架ok,那么不可能还是0
{
pthread_join( thread[0], NULL
);
//!> 等待线程1结束,不结束不执行下面代码
printf("线程1执行结束退出...\n");
}
else
{
printf("线程1创建Error...\n");
exit(
EXIT_FAILURE );
}
if(
thread[1] != 0 )
{
pthread_join( thread[1], NULL
);
//!> 等待线程1结束,不结束不执行下面代码
printf("线程2执行结束退出...\n");
}
else
{
printf("线程2创建Error...\n");
exit(
EXIT_FAILURE );
}
}
int main( )
{
printf("主函数:下面创建2个线程共同处理冒泡排序...\n");
pthread_mutex_init( &mutex, NULL );
print_array();
//!> 打印排序前的结果
create_two_thread();
//!> 创建线程
do_and_wait();
//!> 执行线程and等待
printf(
"排序完成:\n" );
print_array();
//!> 打印排序后的结果
return
0;
}
5.线程清理处理程序
//
线程清理处理程序TEST
#include
#include
#include
void clean(void *arg)
{
printf("清理:
%s \n", (char *)arg);
}
void * entrance( void * arg )
{
printf("线程开始...\n");
pthread_cleanup_push( clean, "线程处理程序1" );
pthread_cleanup_push( clean, "线程处理程序2" );
printf("pthread clean 完成...\n");
sleep(3);
pthread_exit((void
*)0);
//!> 我们知道:清理函数只有在异常退出时候才会做一些清理工作
//!> 所以此处的退出是异常退出来测试的!
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
}
int main( )
{
pthread_t
tid;
void
*
ret = NULL;
if( (
pthread_create( &tid, NULL, entrance, (void *)1 ) )
!= 0 )
{
printf("创建线程失败...\n");
exit(
EXIT_FAILURE );
}
pthread_join( tid, &ret
);
if( ret
)
//!> 注意此处相当于是抛出异常
{
//!> 避免子线程的异常退出造成的空指针情况
printf(
"结束:code == %d\n", *( ( int * ) ret) );
}
return
0;
}
/////////////////////////////////////////////////////////////
//
DEMO——2
#include
#include
#include
void clean( void * arg )
{
printf("清理函数执行...\n");
}
void * entrance( void * arg )
{
int
old_type, old_state;
int i =
0;
pthread_cleanup_push( clean, NULL
);
//!> 设置清理函数
printf("下面设置对本线程的“取消”无效\n");
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE,
&old_state );
//!> 设置对本线程的“取消”无效
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&old_type);
//>>>>>>>>>>>
目标句1
while( 1
)
{
++i;
printf("子线程runing...\n");
sleep( 2
);
if( 5 == i
)
{
printf("下面取消设置对本线程的“取消”无效\n");
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
&old_state);
}
}
pthread_cleanup_pop( 0 );
}
int main( int argc, char ** argv )
{
pthread_t
tid;
int
res;
void
*
ret;
pthread_create( &tid, NULL, entrance, NULL );
sleep( 2
);
printf("请求子线程退出...\n");
pthread_cancel( tid
);
//!> 请求子线程退出
res =
pthread_join( tid, &ret
);
//!> 等待子线程退出
if( ret !=
PTHREAD_CANCELED
)
//!> 非安全退出
{
printf("pthread_join 失败...\n");
exit(
EXIT_FAILURE );
}
else
{
printf("Success..");
}
exit(
EXIT_SUCCESS
);
}
分析:
没有加上“目标句”的结果是:
下面设置对本线程的“取消”无效
子线程runing...
请求子线程退出...
子线程runing...
子线程runing...
子线程runing...
子线程runing...
下面取消设置对本线程的“取消”无效
子线程runing...
//!> 比下面多的
清理函数执行...
Success..
//!> 与下面不一样的
加上后:
下面设置对本线程的“取消”无效
子线程runing...
请求子线程退出...
子线程runing...
子线程runing...
子线程runing...
子线程runing...
下面取消设置对本线程的“取消”无效
清理函数执行...
pthread_join
失败...
//!> 与上面不一样的
这句的作用是将取消类型设置为PTHREAD_CANCEL_ASYNCHRONOUS,即取消请求会被立即响应
那么就不会再次进入等待下一个“取消点”再进行取消!!!
注意:if在while中没有sleep,那么程序会无限run,我们知道sleep是相当于是释放一下线程,那么此时的主线程中的cancel信号又被
接收到,那么if本函数可以响应了,那么就cancle了,if将sleep去掉,那么死循环!再次解释:所谓pthread_cancel仅仅是请求某
个线程退出,那么究竟是不是退出还要看state和type的设置!
6. pthread_once
工作原理code
//
pthread_once
函数使用
#include
#include
#include
pthread_once_t
once =
PTHREAD_ONCE_INIT;
//!> once宏赋值
//!> 初始化执行函数
void once_init( void )
{
printf("初始化成功! 我的ID == %d\n", (unsigned)pthread_self());
}
//!> 线程入口函数
void * entrance( void * arg )
{
printf("子线程:ID == %d \n", (unsigned)pthread_self());
//!> once =
PTHREAD_ONCE_INIT;
//!> 测试使用(下面的要求)
pthread_once( &once, once_init
);
//!> 此处也有初始化
}
//!> main函数
int main( int argc, char * argv[] )
{
pthread_t
pid;
pthread_create( &pid, NULL, entrance, NULL );
printf("主函数ID == %d \n", (unsigned)pthread_self());
//!>
pthread_join( pid, NULL
);
//!> 分析点
pthread_once( &once, once_init
);
//!> 调用一次初始化函数
pthread_join( pid, NULL );
return
0;
}
if
pthread_join是在主函数初始化后面,那么就是主函数初始化的
结果是: 主函数ID
== 441960192
初始化成功! 我的ID == 441960192
子线程:ID == 433944320
显而易见是主函数初始化的!
if
pthread_join是在之前,那么就是要等待子函数执行ok后才执行自己的下面代码
但是此时已经初始化ok了,所以不在初始化!
结果是:主函数ID ==
210818816
子线程:ID == 202802944
初始化成功! 我的ID == 202802944
显然是子函数执行的初始化!
本质:
其实就是操作once变量而已,与互斥变量的本质是一样的!!!
我们可以这样测试在entrance中加入once = PTHREAD_ONCE_INIT;
结果是:主函数ID ==
1590228736
初始化成功! 我的ID == 1590228736
子线程:ID == 1582212864
初始化成功! 我的ID == 1582212864
感兴趣的可以使用pthread_mutex_t 的互斥变量处理,效果一样!
还有最最简单的就是bool值处理!此处不建议!
7.pthread_key_create线程键 与
线程存储
#include
#include
#include
pthread_once_t
once =
PTHREAD_ONCE_INIT;
pthread_key_t
key;
//!> 键值
int
g_val =
10;
//!> 传说中的独享值,呵呵
void once_init_key()
{
if(
pthread_key_create( &key, NULL ) == 0
)
//!> 创建线程键值
{
//!>
printf("创建线程键OK ...\n");
}
}
void * entrance( void * arg )
{
int *
val;
printf("子线程:ID == %d \n", (unsigned)pthread_self());
pthread_setspecific( key, &g_val
);
//!> 将 g_val 作为一个每个进程的独享值
val = ( int
* )pthread_getspecific( key
);
//!> 取出那个值
//!> 此后对于这些量都有自己的处理方式,
//!>
名称相同但是内容不同!!!
//!> 对于文件的处理是最好的!!!
printf("ID
== %d, Value == %d\n", (unsigned)pthread_self(),
*val);
}
int main( )
{
pthread_t
tid,
tid2;
void
*
ret1;
void
*
ret2;
if(
pthread_create( &tid, NULL, entrance, NULL ) != 0
)
//!> 线程1
{
printf("创建线程1失败...\n");
exit(
EXIT_FAILURE );
}
if(
pthread_create( &tid2, NULL, entrance, NULL ) != 0
)
//!> 线程2
{
printf("创建线程2失败...\n");
exit(
EXIT_FAILURE );
}
printf("主函数:ID == %d \n", (unsigned)pthread_self());
//!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
pthread_once( &once, once_init_key
);
//!> 创建一个键值
//!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
printf("下面等待子线程执行ok... \n");
pthread_join( tid, &ret1
);
//!> 等待线程( 必不可少 )
pthread_join( tid2, &ret2 );
return
0;
}
结果:
主函数:ID ==
1588877056
创建线程键OK
...
子线程:ID ==
1580861184
ID ==
1580861184, Value == 10
下面等待子线程执行ok...
子线程:ID ==
1572468480
ID ==
1572468480, Value == 10