目录
一.线程的概念和使用
线程的概念
- 共享相同地址空间的多个任务
1.进程相关特点
- 进程有独立的地址空间(父子空间也独立)
- Linux为每个进程创建task_struct
- 每个进程都参与内部调度,互不影响
2.线程相关特点
- 很多操作系统引入轻量级进程LWP
- 同一进程中的线程共享相同的地址空间
- Linux不区分线程,进程
- 使用多线程可以避免额外的TLB&cache的刷新
3.共享数据
- 可执行指令
- 静态数据(全局变量)
- 工作目录
- 用户ID&用户组ID
4.私有数据
- 线程ID
- PC(程序计数器)&寄存器
- 堆栈
- 错误号
- 优先级
- 执行状态和属性
线程库pathread
1.创建线程
- 任一线程执行exit会导致整个进程结束
- 查看线程命令(ps -eLf|grep cthread)
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*routine)(void *), void *arg);
/*
thread 线程ID
attr 线程属性,NULL表示默认属性
routine 线程执行的函数
arg 传递给routine的参数,
创建成功返回0,失败返货错误码(无法被perror显示)(使用strerror)
*/
- 创建线程案例
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void *function1(void *args);
void *function2(void *args);
int main(int argc, char const *argv[])
{
pthread_t tid;
int err;
err = pthread_create(&tid, NULL, function1, NULL);
if (err != 0)
{
printf("create thread:%s", strerror(err));
}
sleep(1);
err = pthread_create(&tid, NULL, function2, NULL);
if (err != 0)
{
printf("create thread:%s", strerror(err));
}
sleep(1);
return 0;
}
void *function1(void *args)
{
printf("this is thread function1\n");
}
void *function2(void *args)
{
printf("this is thread function2\n");
}
代码编译问题及解决(转载)
问题描述
- undefined reference to ‘pthread_create’
undefined reference to ‘pthread_join’
问题原因:
pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,需要链接该库。
问题解决
- 在编译中要加 -lpthread参数
gcc thread.c -o thread -lpthread
thread.c为你些的源文件,不要忘了加上头文件#include<pthread.h>
————————————————
版权声明:本文为CSDN博主「李刘强博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/llqkk/article/details/2854558
2.回收线程
- 防止线程变成僵尸线程
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
//void **retval为pthread_exit退出函数的返回值
- 线程分离,线程主动与主控线程断开关系,运行结束后自动释放所有资源,防止产生僵尸线程
int pthread_detach(pthread_t thread);
//成功返回0,失败返回错误码;
- 回收线程案例
3.结束线程
- 结束当前线程
- retval可被其他线程通过pthread_join获取
- 线程私有资源被释放
#include <pthread.h>
void pthread_exit(void *retval);
- 结束&回收线程案例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
void *function1(void *args);
void *function2(void *args);
int main(int argc, char const *argv[])
{
pthread_t tid;
int err;
void *retval;
err = pthread_create(&tid, NULL, function1, NULL);
if (err != 0)
{
printf("create thread:%s", strerror(err));
}
sleep(1);
err = pthread_join(tid, &retval); //回收线程
//printf("retval:%s\n",(char *)retval);
printf("retval:%d\n",(int)retval);
return 0;
}
void *function1(void *args)
{
int ret=5;
printf("this is function thread\n");
sleep(1);
//pthread_exit("function exit");
pthread_exit((void *)ret);
}
4.取消线程
- 发一个信号给线程使其停止
int pthread_cancel(pthread_t thread);
- 当某些属性被设置后线程不会停止
int pthread_setcancelstate(int state,int *oldstate);//是否允许取消
PTHREAD_CANCEL_ENABLE
PTHREAD_CANCEL_DISABLE
//线程只有在看守点才能取消
int pthread_setcanceltype(int state,int *oldstate);//是否延时取消
void pthread_testcancel(void);//使程序运行到看守点
PTHREAD_CANCEL_DEFERRED//使程序运行到看守点
PTHREAD_CANCEL_ASYNCHRONOUS
5.同步和互斥机制
同步机制
- 线程共享同一地址空间
- 线程之间通信容易,可通过全局变量交换数据
- 多个线程访问共享数据时需要同步或互斥机制
同步
- 多个任务按照约定的先后顺序执行
信号量(灯)
- p:如果信号量大于0,申请资源任务继续执行,信号量减一,不大于0,任务阻塞
- v:如果有任务在等待资源,唤醒等待的任务,使其继续运行
posix信号量
- 无名信号量(基于内存的信号量)
- 有名信号量
pthread库
int sem_init(sem_t *sem, int pshared, unsigned int value);
//信号量参数|0/1|信号量初值
//0线程间通信,1进程间通信
int sem_wait(sem_t *sem);//p操作
int sem_post(sem_t *sem);//v操作
读写线程案例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
void *write1(void *args);
void *read1(void *args);
char buffer[100];
sem_t sem;//信号量数据结构
int main(int argc, char const *argv[])
{
pthread_t tid1,tid2;
int err,i=0;
void *retval;
sem_init(&sem,0,0);
err = pthread_create(&tid1, NULL, write1, (void *)i);
if (err != 0)
{
printf("create thread:%s", strerror(err));
}
sleep(1);
err = pthread_join(tid1, &retval); //回收线程
err = pthread_create(&tid2, NULL, read1, (void *)i);
if (err != 0)
{
printf("create thread:%s", strerror(err));
}
sleep(1);
err = pthread_join(tid2, &retval); //回收线程
while (1)
{
sleep(1);
}
return 0;
}
void *write1(void *args)
{
int a = 0;
a = (int)args;
int td = pthread_self();
pthread_detach(pthread_self());
while (1)
{
fgets(buffer,20,stdin);
sem_post(&sem);//写线程,写完后释放资源,使用v操作
}
}
void *read1(void *args)
{
int a = 0;
a = (int)args;
int td = pthread_self();
pthread_detach(pthread_self());
while (1)
{
memset(buffer,0,100);
sem_wait(&sem);//度线程,等待写线程的资源,p操作]
printf("%s\n",buffer);
}
}
错误及解决方案
error: conflicting types for ‘write’
情况1:未实现声明函数
情况2:函数名和头文件中已定义的函数名同名
解决方案:修改函数名
互斥机制
临界资源
- 一次只允许一个任务(进程,线程)访问的共享资源
临界区
- 访问临界区的代码
互斥机制
- mutex互斥锁
- 任务访问临界资源前申请互斥锁,然后释放锁
互斥锁
- 初始化互斥锁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
- 成功返回0,失败返回错误码
- mutex是指向要初始化的互斥锁对象
- attr互斥锁属性,NULL表示属性缺失
- 申请锁
int pthread_mutex_lock(pthead_mutex_t *mutex);
- 成功返回0,失败返回错误码
- 如果无法获取锁,任务阻塞
- 释放锁
int pthread_mutex_unlock(pthead_mutex_t *mutex);
- 成功返回0,失败返回错误码
- 执行完临界区要及时释放
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
void *function1(void *args);
void *function2(void *args);
FILE *fp;
pthread_mutex_t mutex;
int main(int argc, char const *argv[])
{
pthread_t tid, tid1;
int err,i=0;
fp = fopen("1.txt", "w");
if (!fp)
{
perror("fopen1");
return -1;
}
pthread_mutex_init(&mutex, NULL);
err = pthread_create(&tid, NULL, function1,(void *)i);
err = pthread_detach(tid); //回收线程
if (err != 0)
{
printf("create thread:%s", strerror(err));
exit(0);
}
err = pthread_create(&tid1, NULL, function2, (void *)i);
err = pthread_detach(tid1);
if (err != 0)
{
printf("create thread:%s", strerror(err));
exit(0);
}
while (1)
{
sleep(1);
}
}
void *function1(void *args)
{
int a = 0;
a = (int)args;
char *c1 = "HELLO WORLD\n";
char *c2;
int len = strlen(c1);
int td = pthread_self();
pthread_detach(pthread_self());
c2 = c1;
while (1)
{
pthread_mutex_lock(&mutex);
for (int i = 0; i < len; i++)
{
fputc(*c1, fp);
fflush(fp);
c1++;
usleep(10000);
}
pthread_mutex_unlock(&mutex);
c1 = c2;
sleep(1);
}
}
void *function2(void *args)
{
int a = 0;
a = (int)args;
char *c1 = "HOW ARE YOU\n";
char *c2;
int len = strlen(c1);
int td = pthread_self();
pthread_detach(pthread_self());
c2 = c1;
while (1)
{
pthread_mutex_lock(&mutex);
for (int i = 0; i < len; i++)
{
fputc(*c1, fp);
fflush(fp);
c1++;
usleep(10000);
}
pthread_mutex_unlock(&mutex);
c1 = c2;
sleep(1);
}
}