考虑以下伪代码。我有一个带有3个属性的类,每个属性都从不同的方法并行填充。
我会从单独的线程中填充同一类实例的不同属性时遇到麻烦吗?我已经设置了.net fiddle,看来它运行正常。
如果此代码将导致线程问题,那么在填充属性时应使用哪种方法锁定Response类的特定实例?
#include <stdio.h>
// Avoid magic numbers
#define ROWS 8
#define COLS 8
int main(){
int board[ROWS][COLS] = {0};
int currentRow = 4, currentColumn = 4;
int cont = 0, moveNumber = 0, i, j;
// Loop forever
while (1) {
printf("Enter a move: ");
// Make sure user enters a number
while (1 != scanf("%d", &moveNumber)) {
// clear stdin
int c;
while((c = getchar()) != '\n' && c != EOF);
// See https://stackoverflow.com/a/6277391/669576
// for why fgets/sscanf is a better option than scanf
// Prompt user for new input
printf("Enter a valid integer:");
}
// Moved this here
if (moveNumber < 0 || moveNumber > 7) break;
cont++;
// Going to use some temp vars to calculate indices
int tempRow, tempCol;
// Calc new indices
switch (moveNumber) {
case 0:
tempRow = currentRow - 1;
tempCol = currentColumn + 2;
break;
case 1:
tempRow = currentRow - 2;
tempCol = currentColumn + 1;
break;
case 2:
tempRow = currentRow - 2;
tempCol = currentColumn - 1;
break;
case 3:
tempRow = currentRow - 1;
tempCol = currentColumn - 2;
break;
case 4:
tempRow = currentRow + 1;
tempCol = currentColumn - 2;
break;
case 5:
tempRow = currentRow + 2;
tempCol = currentColumn - 1;
break;
case 6:
tempRow = currentRow + 2;
tempCol = currentColumn + 1;
break;
case 7:
tempRow = currentRow + 1;
tempCol = currentColumn + 2;
break;
}
// Make sure we have valid indices
if (tempRow < 0 || tempCol < 0 || tempRow >= ROWS || tempCol >= COLS) {
printf("Illegal move\n");
}
else {
// Update the board
currentRow = tempRow;
currentColumn = tempCol;
board[currentRow][currentColumn] = 1;
// And print
for(i = 0; i < ROWS; i++){
for(j = 0; j < COLS; j++){
printf("%d ", board[i][j]);
}
printf("\n");
}
printf("Total moves: %d\n", cont);
}
}
return 0;
}
答案 0 :(得分:4)
由于只有一个类的实例(保存在response
局部变量中),因此没有什么可以锁定在类级别上。在response
变量传递给这些任务时,会隐式捕获一个闭包,但这只是堆内存中实例的 pointer ,而不是对象本身。
由于每个自动属性的后备字段都是独立的(保存在类实例中的单独内存位置中),并且每个方法都在更新单独的属性(因此也就是单独的字段),因此没有更新冲突。这些支持字段不是相互依赖的。
换句话说,没有两个任务试图同时更新相同的内存位置,因此此代码是线程安全的。
但是,如果您有多个任务可能同时更新 same 项目,则 不是线程安全的,则必须实现锁定机制或将数据存储在本质上是线程安全的对象(例如ConcurrentDictionary
等)中。
答案 1 :(得分:2)
我建议你这样走:
var response = Task<Response>
.Factory
.ContinueWhenAll(new Task<string>[]{task1, task2, task3},
tasks => new Response {
Response1 = tasks[0].Result,
Response2 = tasks[1].Result,
Response3 = tasks[2].Result
})
.Result;