pthread_create 是 POSIX 线程库中的函数,用于创建一个新的线程。
函数原型如下:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数说明:
pthread_create 函数会创建一个新的线程,并在新线程中执行指定的线程函数 start_routine。线程函数的参数可以通过 arg 传递。
pthread_join 是 POSIX 线程库中的函数,用于等待指定的线程终止,并获取线程的退出状态。
函数原型如下:
int pthread_join(pthread_t thread, void **retval);
参数说明:
pthread_join 函数会阻塞当前线程,直到指定的线程终止。一旦线程终止,pthread_join 函数会返回,并将线程的退出状态存储在 retval 指向的位置。如果不需要获取退出状态,可以将 retval 设置为 NULL。
pthread_exit 是 POSIX 线程库中的函数,用于终止当前线程并返回一个退出状态。
函数原型如下:
void pthread_exit(void *retval);
参数说明:
pthread_exit 函数会立即终止当前线程,并将 retval 参数作为线程的退出状态。线程的退出状态可以是任意类型的指针,因为 pthread_exit 函数的参数类型是 void*。
pthread_cancel 是 POSIX 线程库中的函数,用于取消指定的线程。
函数原型如下:
int pthread_cancel(pthread_t thread);
参数说明:
pthread_setcancelstate 是 POSIX 线程库中的函数,用于设置线程的取消状态。
函数原型如下:
int pthread_setcancelstate(int state, int *oldstate);
参数说明:
pthread_setcancelstate 函数用于设置线程的取消状态。取消状态决定了线程是否可以被取消。如果取消状态被设置为 PTHREAD_CANCEL_ENABLE,则线程可以被取消;如果取消状态被设置为 PTHREAD_CANCEL_DISABLE,则线程不会被取消。
当线程被取消时,会根据取消类型的设置来决定线程的行为。取消类型可以通过 pthread_setcanceltype 函数设置。
#include
#include
#include
#include
pthread_t tid[2];
//void *类型的函数可以没有显示的返回值
void *my_thread1(void *arg)
{
for(int i = 0; i < 3; i++)
{
printf("this is my_thread1\n");
sleep(1);
}
//取消线程2
pthread_cancel(tid[1]);
//线程退出
// pthread_exit((void *)100);
return (void *)100;
}
void *my_thread2(void *arg)
{
//修改属性,不能被取消
int old;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
for(int i = 0; i < 5; i++)
{
printf("%s\n", (char *)arg);
sleep(1);
}
}
int main()
{
//1.线程号 2.线程属性 3.线程函数 3.线程函数参数
if(pthread_create(&tid[0], NULL, my_thread1, NULL) != 0)
{
perror("pthread_create");
exit(1);
}
//虽然 "helloworld" 是一个字符串常量,但它在 C 语言中被视为字符数组的首地址,
//因此可以将其传递给 pthread_create 函数作为参数。
if(pthread_create(&tid[1], NULL, my_thread2, "helloworld") != 0)
{
perror("ptherad_create");
exit(2);
}
//主线程一定不能提前结束
//主线程等待,直到两个线程都结束
void *status;
pthread_join(tid[0], &status); //等待子线程结束,回收线程资源
printf("线程1结束: %d\n", (int)status);
pthread_join(tid[1], &status);
printf("线程2结束\n");
return 0;
}
include <stdio.h>
#include
#include
#include
#include
#include
#include
#define MSGKEY 1000
pthread_t tid[2];
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
void *recv_thread(void *arg)
{
int msgid = *(int *)arg;
struct msgbuf m;
while(1)
{
if(msgrcv(msgid, &m, sizeof(m.mtext), 2, 0) == -1)
{
perror("msgrcv");
break;
}
if(!strcmp(m.mtext, "bye"))
{
pthread_cancel(tid[1]);
}
printf("%s\n", m.mtext);
memset(&m, 0, sizeof(m));
}
}
void *send_thread(void *arg)
{
int msgid = *(int *)arg;
struct msgbuf m;
while(1)
{
scanf("%s", m.mtext);
m.mtype = 1; //消息类型
if(msgsnd(msgid, &m, sizeof(m.mtext), 0) == -1)
{
perror("msgsnd");
break;
}
if(!strcmp(m.mtext, "bye"))
{
pthread_cancel(tid[0]);
break;
}
memset(&m, 0, sizeof(m));
}
}
int main()
{
//创建消息队列,IPC_CREAT 标志用于创建新的消息队列,这里使用了 IPC_EXCL 标志,如果消息队列已存在,则返回错误。
int msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL);
if(-1 == msgid)
{
perror("msgget");
exit(1);
}
if(pthread_create(&tid[0], NULL, recv_thread, &msgid) != 0)
{
perror("ptherad_create");
exit(2);
}
if(pthread_create(&tid[1], NULL, send_thread, &msgid) != 0)
{
perror("pthread_create");
exit(3);
}
void *status;
pthread_join(tid[0], &status);
pthread_join(tid[1], &status);
//删除消息队列
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#define MSGKEY 1000
pthread_t tid[2] = {0};
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
void *recv_thread(void *arg)
{
int msgid = *(int *)arg;
struct msgbuf m;
while(1)
{
if(msgrcv(msgid, &m, sizeof(m.mtext), 1, 0) == -1)
{
perror("msgrcv");
break;
}
if(!strcmp(m.mtext, "bye"))
{
pthread_cancel(tid[1]);
break;
}
printf("%s\n", m.mtext);
memset(&m, 0, sizeof(m));
}
}
void *send_thread(void *arg)
{
int msgid = *(int *)arg;
struct msgbuf m;
while(1)
{
scanf("%s", m.mtext);
m.mtype = 2; //消息类型
if(msgsnd(msgid, &m, sizeof(m.mtext), 0) == -1)
{
perror("msgsnd");
break;
}
if(!strcmp(m.mtext, "bye"))
{
pthread_cancel(tid[0]);
break;
}
memset(&m, 0, sizeof(m));
}
}
int main()
{
//获取消息队列
int msgid = msgget(MSGKEY, 0);
if(-1 == msgid)
{
perror("msgget");
exit(1);
}
if(pthread_create(&tid[0], NULL, recv_thread, &msgid) != 0)
{
perror("ptherad_create");
exit(2);
}
if(pthread_create(&tid[1], NULL, send_thread, &msgid) != 0)
{
perror("pthread_create");
exit(3);
}
void *status;
pthread_join(tid[0], &status);
pthread_join(tid[1], &status);
return 0;
}
互斥锁的使用步骤:
pthread_mutex_t mutex;
//静态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//动态初始化
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
注意: 互斥锁的初始化、使用和销毁必须成对出现,以确保正确的互斥访问和资源释放。
例子:
#include
#include
#include
pthread_mutex_t mutex; //定义互斥锁
int g_ticket = 100;
//自定义延时函数
void delay()
{
for(int i = 0; i < 10000; i++)
for(int j = 0; j < 5000; j++);
}
void *sale_ticket(void *arg)
{
int cur;
while(1)
{
pthread_mutex_lock(&mutex);
cur = g_ticket;
if(cur <= 0)
{
pthread_mutex_unlock(&mutex);
break;
}
printf("%ld get %d\n", pthread_self(), cur);
cur--;
g_ticket = cur;
pthread_mutex_unlock(&mutex);
delay();
}
}
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_t tid[5];
for(int i = 0; i < 5; i++)
if(pthread_create(&tid[i], NULL, sale_ticket, NULL) != 0)
{
perror("pthread_create");
break;
}
void *status;
for(int i = 0; i < 5; i++)
{
pthread_join(tid[i], &status);
}
pthread_mutex_destroy(&mutex);
return 0;
}
条件变量(Condition Variable)是一种线程同步机制,用于在多线程编程中实现线程间的等待和通知机制。条件变量允许线程在某个条件满足时等待,同时允许其他线程在条件满足时通知等待的线程继续执行。
条件变量通常与互斥锁(Mutex)结合使用,以实现更复杂的线程同步操作。互斥锁用于保护共享资源,而条件变量用于在线程等待共享资源的条件不满足时进行等待,以及在条件满足时通知等待的线程。
在 POSIX 线程库中,条件变量由 pthread_cond_t 类型表示。使用条件变量时,一般需要配合互斥锁一起使用,以确保线程等待和通知的正确性。
条件变量的基本操作包括:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_wait(&cond, &mutex);
该函数会使当前线程进入等待状态,直到条件变量 cond 被其他线程发出的信号(通知)唤醒。在调用 pthread_cond_wait 之前,需要先获取互斥锁 mutex,以保证线程等待的正确性。
pthread_cond_signal(&cond);
该函数用于向等待在条件变量 cond 上的线程发出一个信号,通知其中的一个线程可以继续执行。被通知的线程会从等待状态中被唤醒,并尝试重新获取互斥锁 mutex。
pthread_cond_broadcast(&cond);
该函数用于向等待在条件变量 cond 上的所有线程发出广播信号,通知它们可以继续执行。所有等待的线程都会被唤醒,并尝试重新获取互斥锁 mutex。
例子:
include <stdio.h>
#include
#include
pthread_mutex_t mutex; //定义互斥锁
pthread_cond_t cond; //第一条件变量
int g_ticket = 100;
//自定义延时函数
void delay()
{
for(int i = 0; i < 10000; i++)
for(int j = 0; j < 5000; j++);
}
void *sale_ticket_a(void *arg)
{
int cur;
while(1)
{
pthread_mutex_lock(&mutex);
cur = g_ticket;
if(cur <= 0)
{
pthread_mutex_unlock(&mutex);
break;
}
//如果票数等于50,唤醒b
if(cur == 50)
{
pthread_cond_signal(&cond);
}
printf("%ld get %d\n", pthread_self(), cur);
cur--;
g_ticket = cur;
pthread_mutex_unlock(&mutex);
delay();
}
}
void *sale_ticket_b(void *arg)
{
int cur;
while(1)
{
pthread_mutex_lock(&mutex);
cur = g_ticket;
if(cur <= 0)
{
pthread_mutex_unlock(&mutex);
break;
}
//如果票数大于50,睡眠
if(cur > 50)
{
pthread_cond_wait(&cond, &mutex);
cur = g_ticket;
}
printf("%ld get %d\n", pthread_self(), cur);
cur--;
g_ticket = cur;
pthread_mutex_unlock(&mutex);
delay();
}
}
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_t tid[2];
if(pthread_create(&tid[0], NULL, sale_ticket_a, NULL) != 0)
{
perror("pthread_create");
exit(1);
}
if(pthread_create(&tid[1], NULL, sale_ticket_b, NULL) != 0)
{
perror("pthread_create");
exit(2);
}
void *status;
for(int i = 0; i < 2; i++)
{
pthread_join(tid[i], &status);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
#include
#include
#include
#include
//表示任务队列结点的结构体
typedef struct Task
{
void (*function)(void *arg);
void *arg;
struct Task *next;
}Task;
//表示线程池
typedef struct ThreadPool
{
//任务队列
Task *queueFront;
Task *queueRear;
//线程的数量
int num;
//线程号
pthread_t *threadID;
//互斥锁和条件变量
pthread_mutex_t mutex;
pthread_cond_t cond;
//关闭线程池的标志位
int shutdown;
}ThreadPool;
//线程处理函数
void *worker(void *arg)
{
ThreadPool *pool = (ThreadPool *)arg;
while (1)
{
pthread_mutex_lock(&pool->mutex);
//如果任务队列为空 且线程池没有被关闭 线程睡眠
while (pool->queueFront == pool->queueRear && pool->shutdown == 0)
{
pthread_cond_wait(&pool->cond, &pool->mutex);
}
//如果线程池被关闭
if (pool->shutdown == 1)
{
pthread_mutex_unlock(&pool->mutex);
printf("线城池被关闭 线程 %ld 退出...\n", pthread_self());
pthread_exit((void *)0);
}
//从任务队列获取(出队)一个任务,并且执行
Task task;
Task *t = pool->queueFront->next;
task.function = t->function;
task.arg = t->arg;
pool->queueFront->next = t->next;
free(t);
if (pool->queueFront->next == NULL)
{
pool->queueRear = pool->queueFront;
}
//释放互斥锁
pthread_mutex_unlock(&pool->mutex);
//执行任务
printf("thread %ld start working ...\n", pthread_self());
task.function(task.arg); //通过函数指针调用函数
printf("thread %ld end working ...\n", pthread_self());
}
}
ThreadPool *create_thread_pool(int num)
{
//申请线程池结构体
ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
if (NULL == pool)
{
fprintf(stderr, "malloc ThreadPool failure\n");
return NULL;
}
//初始化任务队列
pool->queueFront = (Task *)malloc(sizeof(Task));
if (NULL == pool->queueFront)
{
fprintf(stderr, "malloc Task failure\n");
free(pool);
return NULL;
}
pool->queueRear = pool->queueFront;
pool->queueFront->next = NULL;
//初始化线程的数量
pool->num = num;
//初始化线程号
pool->threadID = (pthread_t *)malloc(sizeof(pthread_t) * num);
if (NULL == pool->threadID)
{
fprintf(stderr, "malloc pthread_t failure\n");
free(pool->queueFront);
free(pool);
return NULL;
}
//初始化线程
int i;
for (i = 0; i < num; i++)
{
if (pthread_create(&pool->threadID[i], NULL, worker, pool) != 0)
{
fprintf(stderr, "pthread_create failure\n");
free(pool->queueFront);
free(pool->threadID);
free(pool);
return NULL;
}
pthread_detach(pool->threadID[i]); //线程运行结束后自动释放资源
}
//初始化互斥锁和条件变量
pthread_mutex_init(&pool->mutex, NULL);
pthread_cond_init(&pool->cond, NULL);
//初始化关闭线程池的标志位
pool->shutdown = 0;
return pool;
}
//任务函数
void taskfunc(void *arg)
{
int num = *(int *)arg;
printf("thread %ld is working num = %d ...\n", pthread_self(), num);
sleep(1);
free(arg);
}
void thread_pool_add(ThreadPool *pool, void (*func)(void *), void *arg)
{
pthread_mutex_lock(&pool->mutex);
//进队操作
Task *t = (Task *)malloc(sizeof(Task));
if (NULL == t)
{
fprintf(stderr, "malloc Task failure\n");
return;
}
t->function = func;
t->arg = arg;
t->next = NULL;
pool->queueRear->next = t;
pool->queueRear = t;
pthread_mutex_unlock(&pool->mutex);
pthread_cond_signal(&pool->cond);
}
void thread_pool_destroy(ThreadPool *pool)
{
//关闭线程池
pool->shutdown = 1;
//唤醒所有线程
int i;
for (i = 0; i < pool->num; i++)
{
pthread_cond_signal(&pool->cond);
}
//释放线程号
if (pool->threadID)
free(pool->threadID);
//释放任务队列
while (pool->queueFront->next)
{
Task *t = pool->queueFront->next;
pool->queueFront->next = t->next;
free(t);
}
free(pool->queueFront);
//销毁互斥量和条件变量
pthread_mutex_destroy(&pool->mutex);
pthread_cond_destroy(&pool->cond);
//释放线程池结构体
free(pool);
}
int main()
{
//创建线程池
ThreadPool *pool = create_thread_pool(10);
if (NULL == pool)
{
return -1;
}
printf("线程池创建完成 \n");
sleep(1);
//主线程往任务队列中添加任务,并且唤醒线程池中的线程
int i;
for (i = 0; i < 50; i++)
{
int *n = (int *)malloc(sizeof(int));
*n = i;
//把任务添加到任务队列
thread_pool_add(pool, taskfunc, n);
}
sleep(6);
thread_pool_destroy(pool);
return 0;
}
分析以上代码