在Linux中使用线程
我并不假定你会使用Linux的线程,所以在这里就简单的介绍一下。如果你之前有过多线程方面的编程经验,完全可以忽略本文的内容,因为它非常的初级。
#include <pthread.h>
当然,进包含一个头文件是不能搞定线程的,还需要连接libpthread.so这个库,因此在程序连接阶段应该有类似这样的指令:
1. 第一个例子
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*) void *arg);
#include <stdio.h>
#include <pthread.h>
void* thread( void *arg )
{
printf( "This is a thread and arg = %d.\n", *(int*)arg);
*(int*)arg = 0;
return arg;
}
int main( int argc, char *argv[] )
{
pthread_t th;
int ret;
int arg = 10;
int *thread_ret = NULL;
ret = pthread_create( &th, NULL, thread, &arg );
if( ret != 0 ){
printf( "Create thread error!\n");
return -1;
}
printf( "This is the main process.\n" );
pthread_join( th, (void**)&thread_ret );
printf( "thread_ret = %d.\n", *thread_ret );
return 0;
}
代码1第一个多线程编程例子
is a thread and arg =
10”这个字符串,因为arg这个参数值已经定义好了,就是10。之后线程将arg参数的值修改为0,并将它作为线程的返回值返回给系统。与此同时,主进程做的事情就是继续判断这个线程是否创建成功了。在我们的例子中基本上没有创建失败的可能。主进程会继续输出“This
is the main
process”字符串,然后调用pthread_join()接口与刚才的创建进行合并。这个接口的第一个参数就是新创建线程的句柄了,而第二个参数就会去接受线程的返回值。pthread_join()接口会阻塞主进程的执行,直到合并的线程执行结束。由于线程在结束之后会将0返回给系统,那么pthread_join()获得的线程返回值自然也就是0。输出结果“thread_ret
= 0”也证实了这一点。
2. 线程的合并与分离
int pthread_detach(pthread_t tid);
3. 线程的属性
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destory(pthread_attr_t *attr);
那么线程拥有哪些属性呢?一般地,Linux下的线程有:绑定属性、分离属性、调度属性、堆栈大小属性和满占警戒区大小属性。下面我们就分别来介绍这些属性。
3.1 绑定属性
#include <stdio.h>
#include <pthread.h>
……
int main( int argc, char *argv[] )
{
pthread_attr_t attr;
pthread_t th;
……
pthread_attr_init( &attr );
pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
pthread_create( &th, &attr, thread, NULL );
……
}
3.2 分离属性
pthread_attr_setdetachstat(pthread_attr_t *attr, int detachstate);
它的第二个参数有两个取值:PTHREAD_CREATE_DETACHED(分离的)和PTHREAD_CREATE_JOINABLE(可合并的,也是默认属性)。代码3演示了这个属性的使用。
#include <stdio.h>
#include <pthread.h>
……
int main( int argc, char *argv[] )
{
pthread_attr_t attr;
pthread_t th;
……
pthread_attr_init( &attr );
pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
pthread_create( &th, &attr, thread, NULL );
……
}
3.3 调度属性
struct sched_param {
int sched_priority;
}
int pthread_attr_setschedparam(pthread_attr_t *attr, struct sched_param *param);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_COUNT 12
void show_thread_policy( int threadno )
{
int policy;
struct sched_param param;
pthread_getschedparam( pthread_self(), &policy, ¶m );
switch( policy ){
case SCHED_OTHER:
printf( "SCHED_OTHER %d\n", threadno );
break;
case SCHED_RR:
printf( "SCHDE_RR %d\n", threadno );
break;
case SCHED_FIFO:
printf( "SCHED_FIFO %d\n", threadno );
break;
default:
printf( "UNKNOWN\n");
}
}
void* thread( void *arg )
{
int i, j;
long threadno = (long)arg;
printf( "thread %d start\n", threadno );
sleep(1);
show_thread_policy( threadno );
for( i = 0; i < 10; ++i ) {
for( j = 0; j < 100000000; ++j ){}
printf( "thread %d\n", threadno );
}
printf( "thread %d exit\n", threadno );
return NULL;
}
int main( int argc, char *argv[] )
{
long i;
pthread_attr_t attr[THREAD_COUNT];
pthread_t pth[THREAD_COUNT];
struct sched_param param;
for( i = 0; i < THREAD_COUNT; ++i )
pthread_attr_init( &attr[i] );
for( i = 0; i < THREAD_COUNT / 2; ++i ) {
param.sched_priority = 10;
pthread_attr_setschedpolicy( &attr[i], SCHED_FIFO );
pthread_attr_setschedparam( &attr[i], ¶m );
pthread_attr_setinheritsched( &attr[i], PTHREAD_EXPLICIT_SCHED );
}
for( i = THREAD_COUNT / 2; i < THREAD_COUNT; ++i ) {
param.sched_priority = 20;
pthread_attr_setschedpolicy( &attr[i], SCHED_FIFO );
pthread_attr_setschedparam( &attr[i], ¶m );
pthread_attr_setinheritsched( &attr[i], PTHREAD_EXPLICIT_SCHED );
}
for( i = 0; i < THREAD_COUNT; ++i )
pthread_create( &pth[i], &attr[i], thread, (void*)i );
for( i = 0; i < THREAD_COUNT; ++i )
pthread_join( pth[i], NULL );
for( i = 0; i < THREAD_COUNT; ++i )
pthread_attr_destroy( &attr[i] );
return 0;
}
3.4 堆栈大小属性
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3.5 满栈警戒区属性
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
4. 线程本地存储
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);
void* pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_COUNT 10
pthread_key_t g_key;
typedef struct thread_data{
int thread_no;
} thread_data_t;
void show_thread_data()
{
thread_data_t *data = pthread_getspecific( g_key );
printf( "Thread %d \n", data->thread_no );
}
void* thread( void *arg )
{
thread_data_t *data = (thread_data_t *)arg;
printf( "Start thread %d\n", data->thread_no );
pthread_setspecific( g_key, data );
show_thread_data();
printf( "Thread %d exit\n", data->thread_no );
}
void free_thread_data( void *arg )
{
thread_data_t *data = (thread_data_t*)arg;
printf( "Free thread %d data\n", data->thread_no );
free( data );
}
int main( int argc, char *argv[] )
{
int i;
pthread_t pth[THREAD_COUNT];
thread_data_t *data = NULL;
pthread_key_create( &g_key, free_thread_data );
for( i = 0; i < THREAD_COUNT; ++i ) {
data = malloc( sizeof( thread_data_t ) );
data->thread_no = i;
pthread_create( &pth[i], NULL, thread, data );
}
for( i = 0; i < THREAD_COUNT; ++i )
pthread_join( pth[i], NULL );
pthread_key_delete( g_key );
return 0;
}
5. 线程的同步
5.1 互斥锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destory(pthread_mutex_t *mutex );
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t g_mutex;
int g_lock_var = 0;
void* thread1( void *arg )
{
int i, ret;
time_t end_time;
end_time = time(NULL) + 10;
while( time(NULL) < end_time ) {
ret = pthread_mutex_trylock( &g_mutex );
if( EBUSY == ret ) {
printf( "thread1: the varible is locked by thread2.\n" );
} else {
printf( "thread1: lock the variable!\n" );
++g_lock_var;
pthread_mutex_unlock( &g_mutex );
}
sleep(1);
}
return NULL;
}
void* thread2( void *arg )
{
int i;
time_t end_time;
end_time = time(NULL) + 10;
while( time(NULL) < end_time ) {
pthread_mutex_lock( &g_mutex );
printf( "thread2: lock the variable!\n" );
++g_lock_var;
sleep(1);
pthread_mutex_unlock( &g_mutex );
}
return NULL;
}
int main( int argc, char *argv[] )
{
int i;
pthread_t pth1,pth2;
pthread_mutex_init( &g_mutex, NULL );
pthread_create( &pth1, NULL, thread1, NULL );
pthread_create( &pth2, NULL, thread2, NULL );
pthread_join( pth1, NULL );
pthread_join( pth2, NULL );
pthread_mutex_destroy( &g_mutex );
printf( "g_lock_var = %d\n", g_lock_var );
return 0;
}
5.2 条件变量
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destory(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const timespec *abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define BUFFER_SIZE 5
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
typedef struct {
char buf[BUFFER_SIZE];
int count;
} buffer_t;
buffer_t g_share = {"", 0};
char g_ch = 'A';
void* producer( void *arg )
{
printf( "Producer starting.\n" );
while( g_ch != 'Z' ) {
pthread_mutex_lock( &g_mutex );
if( g_share.count < BUFFER_SIZE ) {
g_share.buf[g_share.count++] = g_ch++;
printf( "Prodcuer got char[%c]\n", g_ch - 1 );
if( BUFFER_SIZE == g_share.count ) {
printf( "Producer signaling full.\n" );
pthread_cond_signal( &g_cond );
}
}
pthread_mutex_unlock( &g_mutex );
}
printf( "Producer exit.\n" );
return NULL;
}
void* consumer( void *arg )
{
int i;
printf( "Consumer starting.\n" );
while( g_ch != 'Z' ) {
pthread_mutex_lock( &g_mutex );
printf( "Consumer waiting\n" );
pthread_cond_wait( &g_cond, &g_mutex );
printf( "Consumer writing buffer\n" );
for( i = 0; g_share.buf[i] && g_share.count; ++i ) {
putchar( g_share.buf[i] );
--g_share.count;
}
putchar('\n');
pthread_mutex_unlock( &g_mutex );
}
printf( "Consumer exit.\n" );
return NULL;
}
int main( int argc, char *argv[] )
{
pthread_t ppth, cpth;
pthread_mutex_init( &g_mutex, NULL );
pthread_cond_init( &g_cond, NULL );
pthread_create( &cpth, NULL, consumer, NULL );
pthread_create( &ppth, NULL, producer, NULL );
pthread_join( ppth, NULL );
pthread_join( cpth, NULL );
pthread_mutex_destroy( &g_mutex );
pthread_cond_destroy( &g_cond );
return 0;
}
此外,利用条件变量和互斥锁,可以模拟出很多其它类型的线程同步机制,比如:event、semaphore等。
在Linux中使用线程的更多相关文章
- Linux中-POSIX 线程详解
一种支持内存共享的简捷工具 摘自https://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/ 线程是有趣的 了解如何正确运用线 ...
- 每天进步一点点——Linux中的线程局部存储(一)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/26469435 在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同 ...
- 每天进步一点点——Linux中的线程局部存储(二)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/26876231 在Linux中另一种更为高效的线程局部存储方法,就是使用keyword ...
- Linux中epoll+线程池实现高并发
服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理.通常多线程模型下,每个线程 ...
- linux中的线程同步:生产者、消费者问题
#include <stdio.h> #include <semaphore.h> #include <unistd.h> #include <stdlib. ...
- linux中的线程局部存储(TLS)
http://blog.csdn.net/cywosp/article/details/26469435
- Linux查看进程线程个数
1.根据进程号进行查询: # pstree -p 进程号 # top -Hp 进程号 2.根据进程名字进行查询: # pstree -p `ps -e | grep server | awk '{pr ...
- Linux中的task,process, thread 简介
本文的主要目的是介绍在Linux内核中,task,process, thread这3个名字之间的区别和联系.并且和WINDOWS中的相应观念进行比较.如果你已经很清楚了,那么就不用往下看了. LINU ...
- linux内核中创建线程方法
1.头文件 #include <linux/sched.h> //wake_up_process() #include <linux/kthread.h> //kthread_ ...
随机推荐
- LeetCode 289. Game of Life (生命游戏)
According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellul ...
- 学习笔记 intent属性
Android开发学习笔记:Intent的简介以及属性的详解 2011-08-08 17:20:48 标签:Intent 移动开发 Android 休闲 详解 原创作品,允许转载,转载时请务必以超链接 ...
- CodePath Android CliffNotes 之 Effective Java for Android 翻译
概述: 这篇文章的目的是作为这篇博文的开源版本,而netcyrax是该指南的原始文章的唯一作者. 请在下面添加您自己的在Android中Java最佳实践.技巧和巧妙! 建造者模式 当你拥有一个需要超过 ...
- Apache和Tomcat整合(一个Apache 不同域名处理多个不同业务)
一.简介 在项目中,几乎任何一个项目都包括静态资源和动态请求两大部分.特别对于门户网站这样的项目,静态内容资源会更多,我们使用一般的 Tomcat 部署时,Tomcat 对静态资源的处理能力比较慢,至 ...
- 剖析Linux系统调用的执行路径
在什么是操作系统这篇文章中,介绍过操作系统像是一个代理一样,为我们去管理计算机的众多硬件,我们需要计算机的一些计算服务.数据管理的服务,都由操作系统提供接口来完成.这样做的好处是让一般的计算机使用者不 ...
- 特征提取方法: one-hot 和 IF-IDF
one-hot 和 IF-IDF是目前最为常见的用于提取文本特征的方法,本文主要介绍两种方法的思想以及优缺点. 1. one-hot 1.1 one-hot编码 什么是one-hot编码?one-ho ...
- javascript中new操作符
当代码var p= new Person("tom")执行时,其实内部做了如下几件事情: 1.创建一个空白对象(new Object()). 2.拷贝Person.prototyp ...
- Java面试题解构
有次一个同事让我一同去面试一个候选人,没仔细看简历,所以在问了设计模式之后就让他谈一谈对内存泄漏和垃圾回收的理解,当时候选人一下子就懵了.后来才知道,他面的是初.中级开发职位,想来估计候选人心里也在骂 ...
- Python 解决面试题47 不用加减乘除做加法
在看<剑指Offer>过程中,面试题47不用加减乘除做加法,给出的思路是使用二进制的异或以及与运算,总之就是使用二进制.但是在使用Python实现的过程中,对于正整数是没有问题的,但是对于 ...
- flask中使用xlsxwriter导出excel文件
最近需要使用flask导出xlsxwriter生成的excel文件,在文件比较小的情况下,可以直接导出. 首先,这里使用了StringIO,导出使用的模块 import xlsxwriter impo ...