C语言线程基础

线程的概念
一个正在运行的函数
posix线程是一套标准,而不是实现openmp线程
线程标识: pthread_ t
pthread_equal()

int pthread_equal(pthread_t t1, pthread_t t2);
/*
	功能:比较两个线程ID是否相等。

pthread_self()

获取调用线程ID

pthread_create()

int pthread_create(pthread_t *thread tidp, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

参数
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
功能
线程可以通过调用pthread_self函数获得自身线程标识。创建线程调用pthread_create函数

实例

#include<stdio.h> 
#include<stdlib.h>
#include<pthread.h>
#include <errno.h>
void *func(void *arg)
{
	puts("Thread is working!");
	return NULL;
}
int main()
{
	pthread_t tid;
	int err;
	puts("begin!");
	err = pthread_create(&tid,NULL,func,NULL);
	if(err)
	{
		
		fprintf(stderr,"pthread_create():%s\n",strerror(err));
	    exit(1);
	}
	puts("End!");
	exit(0);
}

请添加图片描述
线程终止和栈处理
线程的终止
3种方式:
(1) 线程从启动例程返回,返回值就是线程的退出码
(2)线程可以被同一进程中的其他线程取消
(3)线程调用pthread_ exit()函数

void pthread_exit( void * value_ptr );

线程的终止可以是调用了pthread_exit或者该线程的例程结束。也就是说,一个线程可以隐式的退出,也可以显式的调用pthread_exit函数来退出。
pthread_exit函数唯一的参数value_ptr是函数的返回代码,只要pthread_join中的第二个参数value_ptr不是NULL,这个值将被传递给value_ptr。
函数原型如下:

int pthread_join( pthread_t  thread, void * * value_ptr );

函数pthread_join的作用是,等待一个线程终止。
调用pthread_join的线程将被挂起直到参数thread所代表的线程终止时为止。pthread_join是一个线程阻塞函数,调用它的函数将一直等到被等待的线程结束为止
如果value_ptr不为NULL,那么线程thread的返回值存储在该指针指向的位置。该返回值可以是由pthread_exit给出的值,或者该线程被取消而返回PTHREAD_CANCELED。
这上面两个转载于https://blog.csdn.net/zhou1021jian/article/details/71531699

#include<stdio.h> 
#include<stdlib.h>
#include<pthread.h>

void *func(void *arg)
{
	puts("Thread is working!");
	pthread_exit(NULL);
	//return NULL;
}
int main()
{
	pthread_t tid;
	int err;
	puts("begin!");
	err = pthread_create(&tid,NULL,func,NULL);
	if(err)
	{
		
	    //fprintf(stderr,"pthread_create():%s\n",strerror(err));
            printf("pthread_create()");
	    exit(1);
	}
	pthread_join(tid,NULL);
	puts("End!");
	exit(0);
}

请添加图片描述
请添加图片描述
请添加图片描述

#include<stdio.h> 
#include<stdlib.h>
#include<pthread.h>

static void cleanup_func(void *arg)
{
	puts(arg);
}
void *func(void *arg)
{
	puts("Thread is working!");
	pthread_cleanup_push(cleanup_func,"cleanup:1");
	pthread_cleanup_push(cleanup_func,"cleanup:2");
    pthread_cleanup_push(cleanup_func,"cleanup:3");
	puts("push over!");
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
	pthread_exit(NULL);
	//return NULL;
}
int main()
{
	pthread_t tid;
	int err;
	puts("begin!");
	err = pthread_create(&tid,NULL,func,NULL);
	if(err)
	{
		
	    //fprintf(stderr,"pthread_create():%s\n",strerror(err));
        printf("pthread_create()");
	    exit(1);
	}
	pthread_join(tid,NULL);
	puts("End!");
	exit(0);
}

请添加图片描述
线程取消
线程的取消选项
线程取消: pthread_ cancel();
取消有2种状态:允许和不允许。
允许取消又分为:异步cancel,推迟cancel(默认)->推迟至cancel点在响应:
cancel点:POSIX定义的canceL点,都是可能引发阻塞的系统调用
pthread_ setcancelstate():设 置是否允许取消
pthread_ setcanceltype():设置取消 方式
pthread_ testcancel():本函数什么都不做,就是一个取消点
线程分离
pthread_detach();
作用:从状态上实现线程分离,注意不是指该线程独自占用地址空间。
线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程),其退出状态不由其他线程获取,而直接自己自动释放(自己清理掉PCB的残留资源)。网络、多线程服务器常用
线程—竞争故障
刚开始创建一个passwd文件,在里面输入1

#include<stdio.h> 
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#define THRNUM 20
#define FNAME "./passwd"
#define LINESIZE 1024
static void *thr_add(void *p)
{
	FILE *fp;
	char linebuf[LINESIZE];
	fp = fopen(FNAME,"r+");
	if(fp == NULL)
	{
		perror("fopen()");
		exit(1);
	}
	fgets(linebuf,LINESIZE,fp);
	fseek(fp,0,SEEK_SET);
	fprintf(fp,"%d\n",atoi(linebuf)+1);
	fclose(fp);
	pthread_exit(NULL);
}
int main()
{
	int i,err;
	pthread_t tid[THRNUM];
	for(i = 0;i < THRNUM;i++)
	{
		err = pthread_create(tid+i,NULL,thr_add,NULL);
		if(err)
		{
			exit(1);
		}
	}
	for(i = 0;i<THRNUM;i++)
	{
		pthread_join(tid[i],NULL);
	}
}

请添加图片描述
互斥锁

pthread_mutex_t lock; /* 互斥锁定义 */
pthread_mutex_init(&lock, NULL); /* 动态初始化,	成功返回0,失败返回非0 */
pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; /* 静态初始化 */
pthread_mutex_lock(&lock); /* 阻塞的锁定互斥锁 */
pthread_mutex_trylock(&thread_mutex)/* 非阻塞的锁定互斥锁,成功获得互斥锁返回0,如果未能获得互斥锁,立即返回一个错误码 */
pthread_mutex_unlock(&lock)/* 解锁互斥锁 */
pthread_mutex_destroy(&lock) /* 销毁互斥锁 */

请添加图片描述
条件变量
条件变量是对全局变量使用的同步机制,一个线程等待条件的成立,另一个线程使当时使条件成立。
条件变量定义

 pthread_cond_t cond;

初始化

 int pthread_cond_init(&cond, NULL); 

销毁

 int pthread_cond_destroy(&cond)

使用条件变量时需要先加互斥锁
• 等待操作:

pthread_mutex_lock (&mutex)
pthread_cond_wait (&cond, &mutex)
pthread_mutex_unlock (&mutex)

• 使条件成立:

pthread_mutex_lock (&mutex)
pthread_cond_signal (&cond)
pthread_mutex_unlock (&mutex)

请添加图片描述
信号量
初始化信号量

int sem_init ((sem_t *__sem, int __pshared, unsigned int __value));

Up操作

int sem_post( sem_t *sem );

用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会唤醒其中一个线程
Down操作

int sem_wait( sem_t *sem );

用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少
销毁信号量

int sem_destroy(sem_t *sem);
volatile int size = 0;//声明为易失型变量
sem_t sem;
/* 从文件读取数据,每读一次,信号量加一*/
void ReadData( void ) {
FILE *fp = fopen( "1.txt", "r" );
while ( !feof( fp ) ) {
fscanf( fp, "%d", &stack[size]);
sem_post( &sem );
++size; }
fclose(fp);
}
/*阻塞等待缓冲区有数据,读取数据后,释放缓冲区,继续循环*/
void HandleData( void ) {
while( 1 ) {
**加粗样式**sem_wait( &sem );
printf( "%d\n", stack[size]);
--size; } }

已下内容转载于https://blog.csdn.net/megayangyang/article/details/55662170
信号量:
信号量是IPC结构中的一种,是进程间通信的一种方法,也可以解决同一进程不同线程之间的通信问题。它是用来保证两个或多个关键代码段不被并发调用,防止多个进程同时对共享资源进行操作。

原理:
在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。

形象理解:
以一个停车场的运作为例。假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。

两种操作:
抽象的来讲,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程/进程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。

  1. Wait(等待)
    当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,要么一直等下去(指放入阻塞队列),直到信号量大于等于一时。
  2. Release(释放)
    实际上是在信号量上执行加一操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为释放了由信号量守护的资源。

两个函数:
sem_post函数(函数原型 int sem_post(sem_t *sem);)
作用是给信号量的值加上一个“1”。 当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是有线程的调度策略决定的。
sem_wait函数(函数原型 int sem_wait(sem_t * sem);)
它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。

一种使用方法:
可以使用信号量完成类似于传递signal的功能:
某一个线程要在一定条件下完成特定功能,由其他多个线程提供条件。此时,其他线程调用sem_post()使信号量加一,本线程调用sem_wait()函数阻塞等待,信号量来了方可退出阻塞。
此种情况本线程只调用sem_wait(),之后不调用sem_post()。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C语言中的Websocket是一种用于在客户端和服务器之间进行双向通信的协议。它使用HTTP协议进行握手,并通过建立持久性连接实现实时通信。 在C语言中,可以使用第三方库,如libwebsockets,来实现Websocket功能。该库提供了一套API,方便开发者在C语言中创建Websocket服务器和客户端。 通过使用libwebsockets,可以轻松地创建一个Websocket服务器。我们需要编写一些回调函数,以处理不同的Websocket事件,如接收到新的连接、接收到消息和连接断开等。这些函数可以在回调函数中执行所需的操作,比如发送消息给客户端或将接收到的消息处理后发送给其他客户端。 对于Websocket客户端,我们可以使用libwebsockets提供的API来连接到服务器。通过设置相应的回调函数,我们可以处理与服务器之间的通信。客户端可以发送消息并处理接收到的消息。 在使用C语言实现Websocket时,需要注意处理并发连接以及数据同步。通过使用合适的线程和锁来确保同一时间只有一个线程访问共享数据,可以避免竞争条件和数据不一致的问题。 总的来说,C语言中的Websocket提供了一种可靠的机制,用于在客户端和服务器之间进行实时双向通信。通过使用合适的库,如libwebsockets,我们可以方便地在C语言中实现Websocket功能。 ### 回答2: C语言是一种非常常用的编程语言,而WebSocket是一种用于实现客户端与服务器之间的双向通信的协议。 WebSocket协议是在HTTP协议基础上建立的,它允许服务器主动向客户端推送数据,而不需要客户端不断地发送请求。这对于需要实时更新数据的应用程序来说非常有用,比如聊天室、实时股票行情等。 在C语言中,我们可以使用第三方的库来实现WebSocket的功能。例如,libwebsockets是一个开源的C库,它提供了WebSocket协议的实现。我们可以使用这个库来在C语言中创建WebSocket服务器或客户端。 在使用libwebsockets库创建WebSocket服务器时,我们需要定义一些回调函数来处理连接、消息等事件。我们可以在回调函数中编写我们的业务逻辑代码,比如处理接收到的消息、发送消息给客户端等。 对于WebSocket客户端的实现,我们可以使用libwebsockets提供的API来创建WebSocket连接,并发送和接收消息。我们可以使用C语言的套接字编程来与WebSocket服务器进行通信。 总结起来,C语言可以通过使用第三方库来实现WebSocket功能。我们可以使用这些库来创建WebSocket服务器或客户端,从而实现客户端与服务器之间的双向通信。 ### 回答3: C语言是一种通用的编程语言,也可以用于开发WebSocket应用程序。WebSocket是一种在客户端和服务器之间实现双向通信的协议,它通过使用常规的HTTP连接进行握手,并通过保持持久连接来实现双向通信。 在C语言中,可以使用第三方库来实现WebSocket通信。例如,libwebsockets是一个流行的C语言库,用于实现WebSocket服务器和客户端。 要使用libwebsockets实现WebSocket服务器,我们需要创建一个基本的C语言程序,并引入libwebsockets头文件。我们可以定义回调函数来处理不同的WebSocket事件,例如接收新的WebSocket连接、收到WebSocket消息等。通过这些回调函数,我们可以实现服务器的逻辑。 要使用libwebsockets实现WebSocket客户端,我们可以创建一个单独的C语言程序,并引入libwebsockets头文件。通过libwebsockets提供的API,我们可以连接到WebSocket服务器,并发送和接收WebSocket消息。 除了libwebsockets外,还有其他一些可用于C语言的WebSocket库,例如WebSocket-C和libwebsock。这些库提供了类似的功能,并且可以根据具体需求进行选择。 总结来说,C语言是一种强大的编程语言,可以用于开发WebSocket应用程序。通过使用适用于C语言的WebSocket库,我们可以实现WebSocket服务器和客户端,从而实现双向通信。这使得C语言成为一个广泛应用于网络通信和实时数据传输的语言

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值