- 线程实质上是进程内一条独立的执行路径,它可以被处理器独立的调度,同时共享进程里的资源。
- 一个进程至少有一个执行线程,线程是在进程内部运行的,本质上是在进程地址空间内运行的。
- 进程是资源分配的基本单位,线程是调度的基本单位。
- 线程几乎不独立拥有资源
#include
#include
#include
#include
#include
void *thread_function(void *arg);
char message[]="Hello World";
int main(){
int res;
pthread_t a_thread;
void *thread_result;
res=pthread_create(&a_thread,NULL,thread_function,(void*)message);
if(res!=0){
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Writing for thread to finish\n");
res=pthread_join(a_thread,&thread_result);
if(res!=0){
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("THread joined,it returned %s\n",(char*)thread_result);
printf("Message is now %s\n",message);
exit(EXIT_SUCCESS);
}
void * thread_function(void *arg){
printf("thread_function is running.Argument was %s\n",(char*)arg);
sleep(3);
strcpy(message,"Bye!");
//这个是等待线程结束的时候的返回值,也就是thread_result的值
pthread_exit("Thank you for the CPU time");
}
[cch@aubin thread]$ gcc thread1.c -pthread
[cch@aubin thread]$ ./a.out
Writing for thread to finish
thread_function is running.Argument was Hello World
THread joined,it returned Thank you for the CPU time
Message is now Bye!
[cch@aubin thread]$
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);第一个参数是线程的类型,第二个参数是线程的属性,第三个是函数指针(线程的入口函数),第四个是给函数指针的参数。该函数的成功会返回一个0,错误会返回一个错误码。
int pthread_join(pthread_t thread, void **retval);以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。参数 :thread: 线程标识符,即线程ID,标识唯一线程。retval: 用户定义的指针,用来存储被等待线程的返回值。返回值 : 0代表成功。 失败,返回的则是错误号。
void pthread_exit(void *value_ptr);线程内部调用该函数用于退出当前线程,参数value_ptr是用于存储线程的退出值传递出去,也可以设为NULL,调用接下来的pthread_join回收线程就可以传出到参数void **value_ptr中。
进程和线程的区别
- 进程是资源调度的基本单位,每一个进程独立的拥有资源。而同一个进程中的线程会共享进程中的资源,包括全局的变量。
pthread_join与pthread_detach的区别
- pthread_create创建线程有两种状态,joinable和unjoinable,也就是可结和与分离的区别,默认是joinable状态。
- 一个可结合的线程能够被其他线程收回其资源和杀死,在被其他线程回收之前,他的存储器资源是不可释放的,所以以默认的属性创建线程时,创建的线程是可结合的,我们需要对线程退出时用pthread_join对线程资源进行回收,只有当pthread_join函数返回的时候,创建的线程才算终止,才会释放自己占用的系统资源。
- 一个不可结合的线程,线程结束后是会自动释放占用的资源。
#include
#include
#include
void* thread_function(void* arg);
int main(){
int res;
pthread_t a_thread;
void *thread_result;
res=pthread_create(&a_thread,NULL,thread_function,NULL);
if(res!=0){
printf("Thread creation failed\n");
exit(EXIT_FAILURE);
}
//res=pthread_detach(a_thread);
res=pthread_join(a_thread,&thread_result);
if(res!=0){
printf("Thread detach failed\n");
exit(EXIT_FAILURE);
}
printf("main finish\n");
while(1){
printf("main running...\n");
sleep(1);
}
exit(EXIT_SUCCESS);
}
void* thread_function(void* arg){
while(1){
printf("thread running...\n");
sleep(1);
}
exit(EXIT_SUCCESS);
}
# pthread_detach运行结果
[cch@aubin thread]$ gcc thread2.c -pthread
[cch@aubin thread]$ ./a.out
main finish
main running...
thread running...
thread running...
main running...
thread running...
main running...
main running...
thread running...
thread running...
main running...
thread running...
main running...
thread running...
main running...
main running...
thread running...
main running...
thread running...
thread running...
main running...
^C
# pthread_join运行结果
[cch@aubin thread]$ gcc thread2.c -pthread
[cch@aubin thread]$ ./a.out
thread running...
thread running...
thread running...
thread running...
thread running...
thread running...
thread running...
thread running...
thread running...
thread running...
^C
[cch@aubin thread]$
进程的资源对进程中的线程是共享的,当线程对进程中的资源进行修改时,如果不对线程的执行的顺序加以控制,会导致数据的混乱。
#include
#include
#include
#include
#include
void *thread_function(void *arg);
int sign=1;//信号量
char message[]="Hello World";
int main(){
int res;
pthread_t a_thread;
void *thread_result;
int print_count1=0;//父线程私有
res=pthread_create(&a_thread,NULL,thread_function,(void*)message);
if(res!=0){
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
while(print_count1++<20){
if(sign==1){
printf("1 ");
fflush(stdout);//强制性输出
sign=2;
}else sleep(1);
}
//printf("Writing for thread to finish\n");
res=pthread_join(a_thread,&thread_result);
if(res!=0){
perror("Thread join failed");
exit(EXIT_FAILURE);
}
//printf("THread joined,it returned %s\n",(char*)thread_result);
//printf("Message is now %s\n",message);
exit(EXIT_SUCCESS);
}
void * thread_function(void *arg){
int print_count2=0;//子线程私有
while(print_count2++<20){
if(sign==2){
fflush(stdout);//强制性输出
printf("2 ");
sign=1;
}else sleep(1);
}
sleep(3);
}
[cch@aubin thread]$ gcc thread1.c -pthread
[cch@aubin thread]$ ./a.out
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 [cch@aubin thread]$
现象:在执行过程中,上述数据是一次性打印的,不是一个个蹦出来的,这是因为linux是有缓冲的,频繁的输入输出会耗费资源,降低性能,所以linux会等待一批数据,然后一次性输出一批数据。可以使用
fflush(stdout);//强制性输出
#include
#include
#include
#include
#include
#include
void *thread_function(void *arg);
sem_t bin_sem;
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int main(){
int res;
pthread_t a_thread;
void *thread_result;
res=sem_init(&bin_sem,0,0);//信号量初始化为0
if(res!=0){
printf("Semaphore initialization failed");
exit(EXIT_FAILURE);
}
res=pthread_create(&a_thread,NULL,thread_function,NULL);
if(res!=0){
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Input some text. Enter 'end' to finish\n");
while(strncmp("end",work_area,3)!=0){
fgets(work_area,WORK_SIZE,stdin);
sem_post(&bin_sem);
}
printf("\nWaiting for thread to finish\n");
res=pthread_join(a_thread,&thread_result);
if(res!=0){
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread join\n");
sem_destroy(&bin_sem);//清除信号资源
exit(EXIT_SUCCESS);
}
void * thread_function(void *arg){
sem_wait(&bin_sem);
while(strncmp("end",work_area,3)!=0){
printf("You input %d characters\n",strlen(work_area)-1);
sem_wait(&bin_sem);
}
pthread_exit(NULL);
}
Input some text. Enter 'end' to finish
shhhhiiihwoojaend
You input 17 characters
ajjq
You input 4 characters
end
Waiting for thread to finish
Thread join
[cch@aubin thread]$
int sem_init(sem_t *sem, int pshared, unsigned int value);sem :指向信号量对象;pshared : 指明信号量的类型。不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享。value : 指定信号量值的大小。sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。int sem_post(sem_t *sem);sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;sem_post() 成功时返回 0;错误时,信号量的值没有更改,-1 被返回,并设置 errno 来指明错误。也即是PV操作中的V操作。int sem_wait(sem_t * sem);sem_wait是一个函数,也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果对一个值为0的信号量调用sem_wait(),这个函数就会原地等待直到有其它线程增加了这个值使它不再是0为止。也就是相当于PV操作中的P操作。函数成功返回0,错误的话信号量的值不改动,返回-1.errno设定来标识错误.#include
///< 创建互斥对象,用指定的初始化属性初始化互斥对象
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
///< 加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
///< 解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
///< 加锁,但是如果对象已经上锁则返回EBUSY错误代码而不阻塞
int pthread_mmutex_trylock(pthread_mutex_t *mutex);
///< 析构并释放mutex相关资源
int pthread_mutex_destroy(pthread_mutex_t *mutex);
互斥锁的使用
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL); ///< 初始化互斥锁
pthread_mutex_lock(&mutex); ///< 加锁
///< 操作公共资源
pthread_mutex_unlock(&mutex); ///< 解锁
pthread_mutex_destroy(&mutex); ///< 销毁互斥锁
#include
#include
#include
#include
#define QUEUE_SIZE 10 //定义缓冲区的大小
int buffer[QUEUE_SIZE];//缓冲区数组
int in=0,out=0;
sem_t full,empty;
pthread_mutex_t lock;//互斥锁
int produce=0;
//生产者线程函数
void *producer(void* arg){
while(1){
produce++;//生产新的产品
sem_wait(&empty);//V
pthread_mutex_lock(&lock);//加锁
buffer[in]=produce;//写入缓冲区
in=(in+1)%QUEUE_SIZE;//更新输入队列指针
printf("Produced %d\n",produce);
pthread_mutex_unlock(&lock);
sem_post(&full);
sleep(2);//等待一段时间,生产下一个数据
}
}
void* consumer(void*arg){
while(1){
sem_wait(&full);
pthread_mutex_lock(&lock);
int consume=buffer[out];//从缓冲区中取数据
out=(out+1)%QUEUE_SIZE;
printf("Comsumed %d\n",consume);
pthread_mutex_unlock(&lock);
sem_post(&empty);
sleep(3);
}
}
int main(){
int res;
sem_init(&empty,0,QUEUE_SIZE);//初始化信号量
sem_init(&full,0,0);
pthread_mutex_init(&lock,NULL);//初始化互斥锁
pthread_t producer_thread,consumer_thread;
//创建
printf("starting......\n");
res=pthread_create(&producer_thread,NULL,&producer,NULL);
if(res!=0){
perror("Produce thread creation failed");
exit(EXIT_FAILURE);
}
res=pthread_create(&consumer_thread,NULL,&consumer,NULL);
if(res!=0){
perror("Consumer thread creation failed");
exit(EXIT_FAILURE);
}
//阻塞
res=pthread_join(producer_thread,NULL);
if(res!=0){
perror("Produce thread join failed");
exit(EXIT_FAILURE);
}
res=pthread_join(consumer_thread,NULL);
if(res!=0){
perror("Consumer thread join failed");
exit(EXIT_FAILURE);
}
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&lock);
exit(EXIT_SUCCESS);
}
[cch@aubin thread]$ ./a.out
starting......
Produced 1
Comsumed 1
Produced 2
Comsumed 2
Produced 3
Comsumed 3
Produced 4
Produced 5
Comsumed 4
Produced 6
Comsumed 5
Produced 7
Produced 8
Comsumed 6
Produced 9
Comsumed 7
Produced 10
Produced 11
Comsumed 8
Produced 12
^C