Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading C-Socket编程中的链表线程安全_Multithreading_Sockets_Linked List_Thread Safety_Pthreads - Fatal编程技术网

Multithreading C-Socket编程中的链表线程安全

Multithreading C-Socket编程中的链表线程安全,multithreading,sockets,linked-list,thread-safety,pthreads,Multithreading,Sockets,Linked List,Thread Safety,Pthreads,我使用线程和TCP在C中实现P2P文件传输。我有一个跟踪程序,它跟踪所有连接到它的对等方。当对等方首次连接时,它会将其文件从当前目录发送到跟踪器,跟踪器将对等方的所有文件放置在共享链接列表中。每个对等体在跟踪器中都有自己的线程,当某个对等体退出时,跟踪器将关闭该对等体的连接,并从链接列表中删除该对等体中的所有文件。我关心的是在添加和删除节点时锁定链接列表。我希望能够安全地从各个线程对链表进行更改。我已经编写了添加/删除链接列表和搜索的代码(不确定搜索时是否需要使用锁定),如何修改代码以确保线程之

我使用线程和TCP在C中实现P2P文件传输。我有一个跟踪程序,它跟踪所有连接到它的对等方。当对等方首次连接时,它会将其文件从当前目录发送到跟踪器,跟踪器将对等方的所有文件放置在共享链接列表中。每个对等体在跟踪器中都有自己的线程,当某个对等体退出时,跟踪器将关闭该对等体的连接,并从链接列表中删除该对等体中的所有文件。我关心的是在添加和删除节点时锁定链接列表。我希望能够安全地从各个线程对链表进行更改。我已经编写了添加/删除链接列表和搜索的代码(不确定搜索时是否需要使用锁定),如何修改代码以确保线程之间的链接安全

最简单的解决方案是在访问列表之前锁定一个
pthread\u mutex\t
,完成后解锁。将其与列表变量一起声明:

struct fileNode *head, *tail;
int numNodes = 0;
pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
例如,添加节点时:

pthread_mutex_lock(&list_lock);
if (numNodes == 0) {
    head = newNode;
    tail = newNode;
    tail->next = NULL;
    numNodes++;
}
else {
    tail->next = newNode;
    tail = newNode;
    tail->next = NULL;
    numNodes++;
}
pthread_mutex_unlock(&list_lock);
或者在遍历列表时:

//check if peer is in the file list
pthread_mutex_lock(&list_lock);
ptr = head;
while(ptr != NULL) {
    // if peer is found
    if((strcmp(ptr->ip, temp_ip) == 0) && ptr->port == temp_port){
        cmd = htonl(200); //set cmd to 1
        break;
    }
    ptr = ptr->next;
}
pthread_mutex_unlock(&list_lock);

由于您的列表很少被访问,所以这应该是好的。如果遇到由该锁引起的可伸缩性问题,则可以移动到更复杂的锁定方案。

< P>请考虑使用互斥体来保护数据或其他资源不受并发访问。< /P> 在POSIX线程的上下文中,
pthread\u mutex\u t
type(from)用于互斥

pthread\u mutex\u lock()
pthread\u mutex\u unlock()
函数()可用于保护链表类型的实例不被这两个操作的并发访问:

  • 读取操作:枚举列表(即读取
    next
    指针)并使用(读取/写入)节点中存储的数据时
  • 写入操作:更改节点:同时更改
    next
    指针和存储在节点中的数据
此外,可以使用相同的互斥锁来保护对
[链接列表]指针的访问

例如:

/。。。
pthread\u mutex\u t list\u mutex=pthread\u mutex\u初始值设定项;
// ...
void*peer_处理程序(void*p)
{
// ...
pthread_mutex_lock(&list_mutex);
如果(节点==0){
头=新节点;
tail=newNode;
tail->next=NULL;
节点++;
}
否则{
tail->next=newNode;
tail=newNode;
tail->next=NULL;
节点++;
}
pthread_mutex_unlock(&list_mutex);
// ...
pthread_mutex_lock(&list_mutex);
结构文件节点*ptr=head;
while(ptr!=NULL){
if((strcmp(ptr->ip,temp\u ip)=0)和&ptr->port==temp\u port){
cmd=htonl(200);
打破
}
ptr=ptr->next;
}
pthread_mutex_unlock(&list_mutex);
// ...
}
无效发送列表(int newsockfd)
{
// ...
pthread_mutex_lock(&list_mutex);
结构文件节点*ptr;
ptr=头部;
while(ptr!=NULL){
// ...
ptr=ptr->next;
// ...
}
pthread_mutex_unlock(&list_mutex);
}
void removeFiles(uint32端口,字符*客户端ip)
{
pthread_mutex_lock(&list_mutex);
// ...
pthread_mutex_unlock(&list_mutex);
}
作废打印()
{
// ...
pthread_mutex_lock(&list_mutex);
结构文件节点*ptr;
ptr=头部;
while(ptr!=NULL){
// ...
ptr=ptr->next;
// ...
}
pthread_mutex_unlock(&list_mutex);
}
值得注意的是,减少锁争用是性能调优并发应用程序的一个重要部分

与套接字相关的问题
send()
recv()
函数不能保证通过一次函数调用发送/接收所有指定的字节数

应使用适当的循环发送或接收所需(预期)字节数。有关其他详细信息,请参阅以下文章:

此外,还应小心此类结构:

n = recv(newsockfd, buffer, sizeof(buffer), 0); 
// ...
buffer[n] = '\0';

要接收的预期字节数(在本例中为字符数)应为
sizeof(buffer)-1
。否则,将丢失数据:最后一个字符将被终止的空字符覆盖。

非常感谢!我应该如何声明&list_lock?@Rachelle:我在问题的开头加了一点说明应该在哪里声明。当我实施锁定时,它影响了我的客户端/服务器,并且不允许服务器接受任何客户端。我遇到了“无效参数”错误。我搞不懂这个怎么知道该锁定哪个列表。@Rachelle:听起来没什么关系。它不需要知道要锁定哪个列表-这只是你需要遵循的一些规则的问题(总是在访问列表之前获取锁)。它如何知道要锁定哪个列表?@Rachelle,互斥锁本身“不知道”要锁定哪个列表。使用互斥锁(锁定和解锁函数调用)访问链接列表类型的一个全局实例«关联»互斥锁与链接列表类型的实例。